代碼示例:
package com.baidu.nuomi.concurrent; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.TimeUnit; /** * Created by sonofelice on 16/6/18. */ public class WaitNotify { static boolean flag = true; static Object lock = new Object(); public static void main(String[] args) throws Exception{ Thread waitThread = new Thread(new Wait(),"WaitThread"); waitThread.start(); TimeUnit.SECONDS.sleep(1); Thread notifyThread = new Thread(new Notify(),"NotifyThread"); notifyThread.start(); } static class Wait implements Runnable{ @Override public void run() { synchronized (lock){ while (flag){ try { System.out.println(Thread.currentThread() + " flag is true. wait @ " + new SimpleDateFormat("HH:mm:ss").format(new Date())); lock.wait(); }catch (InterruptedException e){ } } System.out.println(Thread.currentThread() + "flag is false. running @ " + new SimpleDateFormat("HH:mm:ss").format(new Date())); } } } static class Notify implements Runnable{ @Override public void run() { synchronized (lock){ System.out.println(Thread.currentThread() + "hold lock. notify @ " + new SimpleDateFormat("HH:mm:ss").format(new Date())); lock.notifyAll(); flag = false; SleepUtils.second(5); } synchronized (lock){ System.out.println(Thread.currentThread() + "hold lock again. sleep @ " + new SimpleDateFormat("HH:mm:ss").format(new Date())); SleepUtils.second(5); } } } }
輸出如下:
Thread[WaitThread,5,main] flag is true. wait @ 12:21:04 Thread[NotifyThread,5,main]hold lock. notify @ 12:21:05 Thread[NotifyThread,5,main]hold lock again. sleep @ 12:21:10 Thread[WaitThread,5,main]flag is false. running @ 12:21:15 Process finished with exit code 0
調用wait() notify() notifyAll()方法時需要注意的細節:
1)使用wait() notify() notifyAll() 時需要先對調用對象加鎖;
2)調用wait()方法后,線程狀態由RUNNING 變為WAITING,並將當前線程放置到對象的等待隊列。
3)notify()或notifyAll() 方法調用后,等待線程依舊不會從wait返回,需要調用notify()或notifyAll()的線程釋放鎖之后,等待線程才有機會從wait()返回。
4)notify()方法將等待隊列中的一個等待線程從等待隊列中移到同步隊列中,而notifyAll()方法則是將等待隊列中的所有的線程全部移到同步隊列,被移動的線程狀態由WAITING變為BLOCKED。
5)從wait()方法返回的前提是獲得了調用對象的鎖。
從上面的細節可以看出,等待/通知機制依托於同步機制,其目的就是確保等待線程從wait()方法返回時能夠感知到通知線程對變量做出的修改。
從而抽象出等待/通知的經典范式:
等待方:
1)獲取對象鎖;
2)如果條件不滿足,那么調用對象的wait()方法,被通知后仍要檢查條件。
3)條件滿足則執行對應的邏輯。
對應的偽代碼如下:
synchronized(對象){
while(條件不滿足){
Object.wait();
}
邏輯處理
}
通知方:
1)獲得對象的鎖;
2)改變條件;
3)通知所有等待在對象上的線程。
對應的偽代碼如下:
synchronized(對象){
改變條件
對象.notifyAll();
}