wait
public final void wait()
導(dǎo)致當(dāng)前線程等待,直到另一個(gè)線程為此對(duì)象調(diào)用otify()方法或notifyAll()方法。 換句話說,此方法的行為就像它只是執(zhí)行調(diào)用wait(0)一樣。
當(dāng)前線程必須擁有此對(duì)象的鎖。線程釋放此鎖的所有權(quán)并等待,直到另一個(gè)線程通過調(diào)用notify方法或notifyAll方法通知等待此對(duì)象鎖的線程喚醒。然后線程等待,直到它可以重新獲得鎖的所有權(quán)并繼續(xù)執(zhí)行。
與在單參數(shù)版本中一樣,中斷和虛假喚醒是可能的,并且此方法應(yīng)始終在循環(huán)中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
.. // Perform action appropriate to condition
}
此方法只應(yīng)由持有此對(duì)象鎖的擁有者的線程調(diào)用。有關(guān)線程可以成為鎖擁有者的方式的描述,請(qǐng)參閱notify方法。
示例
Object object = new Object();
object.wait();
上述代碼是否可以正常執(zhí)行?
執(zhí)行結(jié)果如下:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.leofight.concurrency1.MyTest1.main(MyTest1.java:8)
參考api方式修改上述代碼
Object object = new Object();
synchronized (object){
object.wait();
}
上述代碼是否可以執(zhí)行?
執(zhí)行結(jié)果如下:

public final native void wait(long timeout)
導(dǎo)致當(dāng)前線程等待,直到另一個(gè)線程為該對(duì)象調(diào)用notify()方法或notifyAll()方法,或者指定的時(shí)間已經(jīng)過去。
當(dāng)前線程必須擁有此對(duì)象的監(jiān)視器。
該方法導(dǎo)致當(dāng)前線程(稱為T)將自己放入該對(duì)象的等待集中,然后放棄該對(duì)象上的任何和所有同步聲明。線程T在線程調(diào)度時(shí)被禁用,并處于休眠狀態(tài),直到以下四種情況之一發(fā)生:
①其他一些線程調(diào)用此對(duì)象的notify方法,而線程T恰好被任意選擇為要喚醒的線程。
②其他一些線程為該對(duì)象調(diào)用notifyAll方法。
③其他一些線程中斷線程T。
④指定的實(shí)時(shí)時(shí)間或多或少已經(jīng)過了。但是,如果超時(shí)為零,則不考慮實(shí)時(shí),線程只是等待通知。
然后從該對(duì)象的等待集中刪除線程T,并重新啟用線程調(diào)度。然后,它以通常的方式與其他線程競(jìng)爭(zhēng)對(duì)象上的同步權(quán);一旦它獲得了對(duì)對(duì)象的控制,它對(duì)對(duì)象的所有同步聲明都恢復(fù)到以前的狀態(tài)——也就是說,恢復(fù)到調(diào)用wait方法時(shí)的狀態(tài)。然后線程T從wait方法的調(diào)用返回。因此,從wait方法返回時(shí),對(duì)象和線程T的同步狀態(tài)與調(diào)用wait方法時(shí)的同步狀態(tài)完全相同。
線程也可以在不被通知、中斷或超時(shí)的情況下喚醒,這就是所謂的偽喚醒。雖然這種情況在實(shí)踐中很少發(fā)生,但是應(yīng)用程序必須通過測(cè)試應(yīng)該喚醒線程的條件來(lái)防范這種情況,如果條件不滿足,則繼續(xù)等待。換句話說,等待應(yīng)該總是在循環(huán)中發(fā)生,就像這個(gè)
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
有關(guān)此主題的更多信息,請(qǐng)參見Doug Lea的“Java并發(fā)編程(第二版)”中的3.2.3節(jié)。(Addison-Wesley, 2000),或Joshua Bloch的“有效Java編程語(yǔ)言指南”(Addison-Wesley, 2001)中的第50項(xiàng)。
如果當(dāng)前線程在等待之前或等待期間被任何線程中斷,則拋出InterruptedException。在此對(duì)象的鎖狀態(tài)恢復(fù)到如上所述之前,不會(huì)引發(fā)此異常。
注意,wait方法在將當(dāng)前線程放入該對(duì)象的wait集中時(shí),只解鎖該對(duì)象;當(dāng)前線程可能被同步的任何其他對(duì)象在線程等待時(shí)仍然鎖定。
此方法只能由該對(duì)象監(jiān)視器的所有者線程調(diào)用。有關(guān)線程如何成為監(jiān)視器所有者的描述,請(qǐng)參閱notify方法。
sleep
導(dǎo)致當(dāng)前正在執(zhí)行的線程休眠(暫時(shí)停止執(zhí)行)指定的毫秒數(shù),具體取決于系統(tǒng)計(jì)時(shí)器和調(diào)度程序的精度和準(zhǔn)確性。線程不會(huì)失去任何鎖的擁有權(quán)。
小結(jié)
在調(diào)用wait方法時(shí),線程必須要持有被調(diào)用對(duì)象的鎖,當(dāng)調(diào)用wait方法后,線程就會(huì)釋放掉該對(duì)象的鎖(monitor)。
在調(diào)用Thread類的sleep方法時(shí),線程是不會(huì)釋放掉對(duì)象的鎖的。
反編譯示例類
concurrency1 javap -c MyTest1
警告: 二進(jìn)制文件MyTest1包含com.leofight.concurrency1.MyTest1
Compiled from "MyTest1.java"
public class com.leofight.concurrency1.MyTest1 {
public com.leofight.concurrency1.MyTest1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.InterruptedException;
Code:
0: new #2 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>":()V
7: astore_1
8: aload_1
9: dup
10: astore_2
11: monitorenter
12: aload_1
13: invokevirtual #3 // Method java/lang/Object.wait:()V
16: aload_2
17: monitorexit
18: goto 26
21: astore_3
22: aload_2
23: monitorexit
24: aload_3
25: athrow
26: return
Exception table:
from to target type
12 18 21 any
21 24 21 any
}
? concurrency1