前幾天去UC筆試,有一道簡答題問到了。之前還真一直沒留意到這個問題,所以答得也不好。
無論學習什么都好,通過對比學習更有利於發現事物的共性和個性,對於知識點的理解更有明顯效果(這也可能是UC筆試題上,5道簡答題中,有4道都是關於X與Y的區別的問題的原因之一)。
既然自己答得不好,那就寫下這篇隨筆,來警示下自己(不僅是sleep與wait區別,還有多用這種對比學習的學習方式)。
翻了很多資料,說的最多的一句就是,
sleep與wait最主要的區別在於,sleep與wait都可以使線程等待,但sleep不會釋放資源而wait會釋放資源。
還有就是,wait方法只能在同步塊或者同步方法中執行。
怎么理解這句話?
這里有個例子:我登錄圖書管理系統訂了一本 《瘋狂JAVA講義》,當我去到圖書管排隊借書,到了借書窗口的時候,我告訴管理員我們的名字和預定的書,然后管理員查詢到我預訂的信息,然后安排助理去預定的圖書中找這本書,這個時候,如果我用的是sleep模式,我就一直站在窗口前,直到管理員給我這本書。如果我用的是wait模式,那么我就讓出位置給在排隊的后面的同學,到旁邊的椅子上等待,直到通知我,我要的書找到了,我再回到隊伍中排隊取票。
這樣是不是明白對了?
下面來驗證一下,sleep是否不會釋放資源而wait會釋放資源。
public class ThreadTest { public static void main(String[] args) throws InterruptedException { new Thread(new Thread1()).start(); synchronized (ThreadTest.class) { System.out.println("Main Thread go to sleep : currenttime-->"+System.currentTimeMillis()); //sleep過程不會釋放資源 Thread.sleep(10000); } System.out.println("Main Thread get up : currenttime-->"+System.currentTimeMillis()); new Thread(new Thread2()).start(); System.out.println("Main Thread over"); } static class Thread1 implements Runnable{ @Override public void run() { System.out.println("Thread1 is ready :currenttime-->"+System.currentTimeMillis()); //因為sleep不會釋放資源,所以在主線程sleep結束前,是不能取得資源的鎖,而是在等待 synchronized (ThreadTest.class) { System.out.println("Thread1 is running :currenttime-->"+System.currentTimeMillis()); System.out.println("Thread1 wait :currenttime-->"+System.currentTimeMillis()); try { ThreadTest.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1 is over "); } } } static class Thread2 implements Runnable{ @Override public void run() {
System.out.println("Thread2 is ready :currenttime-->"+System.currentTimeMillis()); synchronized (ThreadTest.class){ System.out.println("Thread2 is running :currenttime-->"+System.currentTimeMillis()); System.out.println("Thread2 notify :currenttime-->"+System.currentTimeMillis()); ThreadTest.class.notify(); System.out.println("Thread2 is over"); } } } }
輸出結果:
Main Thread go to sleep : currenttime-->1400232812969
Thread1 is ready :currenttime-->1400232812969
Main Thread get up : currenttime-->1400232822970
Thread1 is running :currenttime-->1400232822970
Thread1 wait :currenttime-->1400232822970
Main Thread over
Thread2 is ready :currenttime-->1400232822972
Thread2 is running :currenttime-->1400232822972
Thread2 notify :currenttime-->1400232822972
Thread2 is over
Thread1 is over
由結果可以看出,當主線程sleep10s中的過程,Thread1僅僅處於ready狀態,而一直沒有獲取到ThreadTest.class的鎖,原因在於,主線程在sleep的之前已經獲取了該資源的鎖,這也驗證了在用sleep()的時候不會釋放資源。
當主線程sleep完之后,Thread1獲取到了ThreadTest.class的鎖,然后調用了wait方法(wait方法是Object的靜態方法)。在調用該方法后,Thread2啟動,且順利獲取到ThreadTest.class的鎖,這也驗證了在用wait()方法的時候會釋放資源。
最后,在Thread2中調用notify方法(notify方法也是Object的靜態方法,作用是喚醒在同步監視器上等待的一個線程),然后我們看到 "Thread1 is over"。wait 方法與 notify 方法或notifyAll方法 搭配使用,來協調線程運行。如果我們把Thread2中的notify方法去掉,會發現最后Thread1並沒有再次運行,也就不會打印"Thread1 is over"。