爲何wait(),notify(),notifyAll()必須在同步方法/代碼塊中調用?

    在JAVA中,全部的對象都可以被做爲‘監視器monitor’——指的是一個擁有一個獨佔鎖,一個入口隊列,和一個等待隊列的實體entity。全部對象的非同步方法都能在任意時刻被任意線程調用,此時不須要考慮加鎖的問題。而對於對象的同步方法來講, 在任意時刻有且僅有一個擁有該對象獨佔鎖的線程可以調用它們。 例如,一個同步方法是獨佔的。若是在線程調用某一個對象的同步方法的時候,對象的獨佔鎖被其餘線程佔有,那麼當前線程將處於阻塞狀態。並添加到對象的入口隊列中java

 

    只有在調用線程擁有的某個對象的獨佔鎖的時候,纔可以調用該對象的wait, notify, notifyall方法。這一點一般不會被程序員注意,由於程序驗證一般是在對象的同步方法或同步代碼塊中調用它們的。若是嘗試在未獲取對象鎖時調用這三個方法,那麼你將獲得一個"java.lang.IllegalMonitorStateException:current thread not owner"。程序員

 

    當一個線程正在某一個對象的同步方法中運行時調用了這個對象的wait()方法,那麼這個線程將釋放該對象的獨佔鎖並被放入這個對象的等待隊列。注意,wait()方法強制當前線程釋放對象鎖。這意味着在調用某對象的wait()方法以前,當前線程必須已經得到該對象的鎖所以,線程必須在某個對象的同步方法或同步代碼塊中才能調用該對象的wait()方法線程

 

    當某線程調用某對象的notify()或notifyAll()方法時,任意一個(對於notify())或者全部(對於notifyAll())在該對象的等待隊列中的線程,將被轉移到該對象的入口隊列。接着這些隊列(譯者注:可能只有一個)將競爭該對象的鎖,最終得到鎖的線程繼續執行。若是沒有線程在該對象的等待隊列中等待得到鎖,那麼notify()和notifyAll()將不起任何做用。在調用對象的notify()和notifyAll()方法以前,調用線程必須已經獲得該對象的鎖。所以,必須在某個對象的同步方法或同步代碼塊中才能調用該對象的notify()或notifyAll()方法對象

 

    對於處於某對象的等待隊列中的線程,只有當其餘線程調用此對象的notify()或notifyAll()方法時纔有機會繼續執行。隊列

    調用wait()方法的緣由一般是,調用線程但願某個特殊的狀態(或變量)被設置以後再繼續執行。調用notify()或notifyAll()方法的緣由一般是,調用線程但願告訴其餘等待中的線程:"特殊狀態已經被設置"。這個狀態做爲線程間通訊的通道,它必須是一個可變的共享狀態(或變量)。同步

    例如,生產者線程向緩衝區中寫入數據,消費者線程從緩衝區中讀取數據。消費者線程須要等待直到生產者線程完成一次寫入操做。生產者線程須要等待消費者線程完成一次讀取操做。假設wait(),notify(),notifyAll()方法不須要加鎖就可以被調用。此時消費者線程調用wait()正在進入狀態變量的等待隊列(譯者注:可能還未進入)。在同一時刻,生產者線程調用notify()方法打算向消費者線程通知狀態改變。那麼此時消費者線程將錯過這個通知並一直阻塞。所以,對象的wait(),notify(),notifyAll()方法必須在該對象的同步方法或同步代碼塊中被互斥地調用。it

相關文章
相關標籤/搜索