Java多线程通信lock和wait

  • 2020 年 1 月 21 日
  • 笔记

在Java多线程中有一对配合使用过的两个方法,来实现线程间通信的功能–lock和wait, 由于这个需要获得锁,所以必须结合synchronized一起使用。首先我们先看一个例子:

  public class LockWait {    	static volatile List<String> itemContainer = new ArrayList<>();  	static Object obj = new Object();    	public static void main(String[] args) {  		Thread th1 = new Thread(() -> {  			synchronized (obj) {  				for (int i = 0; i < 10; i++) {  					System.out.println("th1添加元素");  					itemContainer.add(String.valueOf(i));  					if (itemContainer.size() == 5) {  						System.out.println("th1线程发出通知");  						obj.notify();  					}  				}  			}  		});    		Thread th2 = new Thread(() -> {  			synchronized (obj) {  				System.out.println("进入th2线程");  				if (itemContainer.size() != 5) {  					try {  						System.out.println("th2线程开始等待");  						obj.wait();  						System.out.println("th2线程等待结束");  					} catch (InterruptedException e) {  						e.printStackTrace();  					}  					System.out.println("th2线程结束");  				}  			}    		});    		th2.start();  		th1.start();  	}  }

输出结果如下:

进入th2线程  th2线程开始等待  th1添加元素  th1添加元素  th1添加元素  th1添加元素  th1添加元素  th1线程发出通知  th1添加元素  th1添加元素  th1添加元素  th1添加元素  th1添加元素  th2线程等待结束  th2线程结束

具体运行逻辑如下:

总结上面的运行结果,th2在wait的时候,th1可以持有锁。说明wait是释放锁,而notify不释放锁。

这样也就带来了一个弊端,无法实时的得到结果,就是说当List达到我们想要的结果的时候,th1线程一直还在持有锁,导致th2无法执行。

有没有更好办法呢?在Java中提供了一个CountDownLatch类:

public class CountDownLatchTest {    	public static void main(String[] args) {  		final List<String> itemContainer = new ArrayList<>();  		final CountDownLatch countDownLanch = new CountDownLatch(1);  		Thread th1 = new Thread(() -> {  			for (int i = 0; i < 10; i++) {  				try {  					System.out.println("th1添加元素");  					itemContainer.add(String.valueOf(i));  					if (itemContainer.size() == 5) {  						System.out.println("th1线程发出通知");  						countDownLanch.countDown();  					}  				} catch (Exception e) {  					e.printStackTrace();  				}    			}  		});    		Thread th2 = new Thread(() -> {  			System.out.println("进入th2线程");  			if (itemContainer.size() != 5) {  				try {  					System.out.println("th2线程开始等待");  					countDownLanch.await();  					System.out.println("th2线程等待结束");  				} catch (InterruptedException e) {  					e.printStackTrace();  				}  				System.out.println("th2线程结束");  			}    		});    		th2.start();    		th1.start();  	}  }

运行结果:

进入th2线程  th1添加元素  th2线程开始等待  th1添加元素  th1添加元素  th1添加元素  th1添加元素  th1线程发出通知  th1添加元素  th2线程等待结束  th1添加元素  th2线程结束  th1添加元素  th1添加元素  th1添加元素