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添加元素