釋放同步監視器的時機
- 當前線程的同步代碼塊或同步方法正常執行結束;
- 當前線程在同步代碼塊或同步方法中遇到break或return語句返回;
- 當前線程在執行同步代碼塊或同步方法時發生了未處理的Error或Exception,導致程序異常結束;
- 當前線程在同步代碼塊或同步方法中調用wait()方法。
- 線程在同步代碼塊或同步方法中調用Thread.sleep()或Thread.yield()方法來暫停當前線程的執行;
- 線程在同步代碼塊或同步方法中調用suspend() 方法掛起當前線程(當然,我們應該儘量避免使用suspend()和resume()方法來控制線程)。
wait()
<span style="font-size:14px;">public final void wait() throws InterruptedException, IllegalMonitorStateException</span>
該方法用來將當前線程置入休眠狀態,直到接到通知或被中斷爲止。在調用wait()之前,線程必須要獲得該對象的對象級別鎖,即只能在同步方法或同步塊中調用wait()方法。調用wait()方法後當前線程會釋放鎖。在從wait()返回前,當前線程與其他線程競爭重新獲得鎖。如果調用wait()方法時,沒有持有適當的鎖,則拋出IllegalMonitorStateException,它是RuntimeException的一個子類,因此不需要try-catch結構。notify()
public final native void notify() throws IllegalMonitorStateException
該方法也要在同步方法或同步塊中調用,如果調用notify()時沒有持有適當的鎖,也會拋出IllegalMonitorStateException。notify()方法用來通知那些可能等待該對象級別鎖的其他線程。如果有多個線程在等待同一把鎖,則線程規劃器會任意挑選出其中一個wait()狀態的線程來發出通知,並使它等待獲取該對象的對象級別鎖。注意,調用notify()方法後,當前線程不會馬上釋放該對象級別鎖,必須要等到線程退出同步代碼塊或同步方法後纔會釋放對象級別鎖,wait狀態的線程纔可以獲取該對象鎖。
notifyAll()
public final native void notifyAll() throws IllegalMonitorStateException
該方法與notify()方法的工作方式基本相同,不同的地方在於notifyAll()會使所有原來在該對象上wait的線程統統退出wait的狀態(即全部被喚醒,不再等待notify或notifyAll,但由於此時還沒有獲取到該對象鎖,因此還不能繼續往下執行),變成等待獲取該對象上的對象級別鎖,一旦該對象鎖被釋放,他們就會立即去競爭。如果其中一個線程獲得了該對象鎖,它就會繼續往下執行,其他線程繼續等待。在該線程退出同步代碼塊或同步方法釋放鎖後,其他的已經被喚醒的線程將會繼續競爭獲取該對象鎖,一直進行下去,直到所有被喚醒的線程都執行完畢。