void notify() Wakes up a single thread that is waiting on this object’s monitor. 譯:喚醒在此對象監視器上等待的單個線程 void notifyAll() Wakes up all threads that are waiting on this object’s monitor. 譯:喚醒在此對象監視器上等待的所有線程 void wait( ) Causes the current thread to wait until another thread invokes the notify() method or the notifyAll( ) method for this object. 譯:導致當前的線程等待,直到其他線程調用此對象的notify( ) 方法或 notifyAll( ) 方法 void wait(long timeout) Causes the current thread to wait until either another thread invokes the notify( ) method or the notifyAll( ) method for this object, or a specified amount of time has elapsed. 譯:導致當前的線程等待,直到其他線程調用此對象的notify() 方法或 notifyAll() 方法,或者指定的時間過完。 void wait(long timeout, int nanos) Causes the current thread to wait until another thread invokes the notify( ) method or the notifyAll( ) method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed. 譯:導致當前的線程等待,直到其他線程調用此對象的notify( ) 方法或 notifyAll( ) 方法,或者其他線程打斷了當前線程,或者指定的時間過完。
上面是官方文檔的簡介,下面我們根據官方文檔總結一下:
-
wait( ),notify( ),notifyAll( )都不屬於Thread類,而是屬於Object基礎類,也就是每個對象都有wait( ),notify( ),notifyAll( ) 的功能,因為每個對象都有鎖,鎖是每個對象的基礎,當然操作鎖的方法也是最基礎了。
-
當需要調用以上的方法的時候,一定要對競爭資源進行加鎖,如果不加鎖的話,則會報 IllegalMonitorStateException 異常
-
當想要調用wait( )進行線程等待時,必須要取得這個鎖對象的控制權(對象監視器),一般是放到synchronized(obj)代碼中。
-
在while循環里而不是if語句下使用wait,這樣,會在線程暫停恢復后都檢查wait的條件,並在條件實際上並未改變的情況下處理喚醒通知
-
調用obj.wait( )釋放了obj的鎖,否則其他線程也無法獲得obj的鎖,也就無法在synchronized(obj){ obj.notify() } 代碼段內喚醒A。
-
notify( )方法只會通知等待隊列中的第一個相關線程(不會通知優先級比較高的線程)
-
notifyAll( )通知所有等待該競爭資源的線程(也不會按照線程的優先級來執行)
-
假設有三個線程執行了obj.wait( ),那么obj.notifyAll( )則能全部喚醒tread1,thread2,thread3,但是要繼續執行obj.wait()的下一條語句,必須獲得obj鎖,因此,tread1,thread2,thread3只有一個有機會獲得鎖繼續執行,例如tread1,其余的需要等待thread1釋放obj鎖之后才能繼續執行。
-
當調用obj.notify/notifyAll后,調用線程依舊持有obj鎖,因此,thread1,thread2,thread3雖被喚醒,但是仍無法獲得obj鎖。直到調用線程退出synchronized塊,釋放obj鎖后,thread1,thread2,thread3中的一個才有機會獲得鎖繼續執行。
測試用例:
1 package test; 2 3 /** 4 * @author zsh 5 * @company wlgzs 6 * @create 2019-02-25 9:02 7 * @Describe 多線程方法wait() and notify() 方法測試 8 */ 9 public class WaitNotifyTest { 10 11 // 在多線程間共享的對象上使用wait 12 private String[] shareObj = {"true"}; 13 14 //線程等待 15 class ThreadWait extends Thread{ 16 17 public ThreadWait(String name){ 18 super(name); 19 } 20 21 @Override 22 public void run() { 23 synchronized (shareObj){ 24 while ("true".equals(shareObj[0])){ 25 System.out.println("線程"+this.getName()+"開始等待"); 26 long startTime = System.currentTimeMillis(); 27 try { 28 shareObj.wait(); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 long endTime = System.currentTimeMillis(); 33 System.out.println("線程"+this.getName()+"等待的時間為"+ 34 (endTime - startTime)); 35 } 36 } 37 System.out.println("線程" + this.getName() + "等待結束"); 38 } 39 } 40 41 //線程喚醒 42 class ThreadNotify extends Thread{ 43 44 public ThreadNotify(String name){ 45 super(name); 46 } 47 48 @Override 49 public void run() { 50 try { 51 // 給等待線程等待時間 52 sleep(3000); 53 } catch (InterruptedException e) { 54 e.printStackTrace(); 55 } 56 synchronized (shareObj){ 57 System.out.println("線程" + this.getName() + "開始准備通知"); 58 shareObj[0] = "false"; 59 shareObj.notifyAll(); 60 System.out.println("線程" + this.getName() + "通知結束"); 61 } 62 System.out.println("線程" + this.getName() + "運行結束"); 63 } 64 } 65 66 public static void main(String[] args) { 67 WaitNotifyTest waitNotifyTest = new WaitNotifyTest(); 68 ThreadWait threadWait1 = waitNotifyTest.new ThreadWait("wait thread1"); 69 /** 70 * 優先級 : 只能反映線程的 重要程度 或者是 緊急程度 , 不能決定 是否一定先執行 71 * setPriority() 72 * 1~10 1最低 10最高 5是默認值 73 */ 74 threadWait1.setPriority(2); 75 ThreadWait threadWait2 = waitNotifyTest.new ThreadWait("wait thread2"); 76 threadWait2.setPriority(3); 77 ThreadWait threadWait3 = waitNotifyTest.new ThreadWait("wait thread3"); 78 threadWait3.setPriority(4); 79 80 ThreadNotify threadNotify = waitNotifyTest.new ThreadNotify("notify thread"); 81 82 threadNotify.start(); 83 threadWait1.start(); 84 threadWait2.start(); 85 threadWait3.start(); 86 } 87 88 89 }