為了更好的支持多線程之間的協作,JDK提供了三個重要的本地方法
//調用某個對象的wait()方法能讓當前線程阻塞,並且當前線程必須擁有此對象的鎖. public final void wait() throws InterruptedException { wait(0); } //調用某個對象的notify()方法能夠喚醒一個正在等待這個對象的鎖的線程,如果有多個線程都在等待這個對象的鎖,則只能喚醒其中一個線程 public final native void notify(); //notifyAll()方法能夠喚醒所有正在等待這個對象鎖的線程; public final native void notifyAll();
如圖:當一個擁有Object鎖的線程調用 wait()方法時,就會使當前線程加入object.wait 等待隊列中,並且釋放當前占用的Object鎖,這樣其他線程就有機會獲取這個Object鎖,獲得Object鎖的線程調用notify()方法,就能在Object.wait 等待隊列中隨機喚醒一個線程(該喚醒是隨機的與加入的順序無關,優先級高的被喚醒概率會高),若果調用notifyAll()方法就喚醒全部的線程。注意:調用notify()方法後並不會立即釋放object鎖,會等待該線程執行完畢後釋放Object鎖。
代碼:
public class WaitTest { private static Object object=new Object(); public static void main(String[] args) { Thread thread=new Thread(){ @Override public void run() { synchronized (object) { System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"進入啟動"); try { object.wait();//使當前線程進入等待(進入Object.wait隊列)並釋放對象鎖 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"線程執行結束"); } } }; thread.start(); Thread thread_2=new Thread(){ @Override public void run() { synchronized (object) { System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"進入啟動"); try { object.notify();//隨機在Object.waitd隊列中喚醒一個正在等待該對象鎖的線程 System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"喚醒一個等待的線程"); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; thread_2.start(); } }
執行結果:
1473306408730:Thread-0進入啟動 1473306408731:Thread-1進入啟動 1473306408731:Thread-1喚醒一個等待的線程 1473306418731:Thread-0線程執行結束
從時間戳中可以看出 Thread-1 在通知Thread-0 繼續執行後,Thread-0 並未立即執行,而是等待Thread-1 釋放Object鎖,在重新獲得Object鎖後,才能繼續執行。(最後兩個時間戳相減剛好是10秒)