破除java神話之執行緒按優先順序喚醒

azz發表於2007-08-24
破除java神話之執行緒按優先順序喚醒[@more@]  在編寫多執行緒程式碼的時候經常發生多個執行緒等待一個事件的情況。這種情況多發生於多個執行緒在同步方法或者同步塊內呼叫wait方法等待同一個被鎖住的物件。當另一個鎖住該物件的執行緒從同步方法或者同步塊中呼叫notify或者notifyAll方法時這些等待執行緒被喚醒。notify呼叫僅僅喚醒一個執行緒,因此如果有多個執行緒正處於等待狀態,那麼不會有對鎖的競爭。另一方面,notifyAll呼叫喚醒所有的等待執行緒而造成競爭,然而只有一個執行緒能夠得到鎖,其它的都會被阻塞。

  當多個執行緒處於等待狀態時的問題是當呼叫notify或者notifyAll方法後哪一個執行緒將執行?很多程式設計師不正確的假定存在一種預定義的順序表明執行緒如何被喚醒。一些認為是高優先順序的執行緒首先被喚醒,另一些可能認為是等待了最長時間的執行緒首先被喚醒。不幸的是上面的假設都是不對的。在這些情況下,哪個執行緒被喚醒是不確定的,也許是最高優先順序的執行緒,也許是等待最長的執行緒,但是沒有保證。

  執行緒的優先順序不能決定它是否被喚醒(在使用notify方法的情況下)或者在多執行緒環境下的喚醒順序(在使用notifyAll方法的情況下)。因此,因此你永遠不應該假設執行緒的喚醒順序。另外,你也永遠不應該對搶佔過程中的執行緒排程做任何假設。執行緒排程是實現相關的(implementation-dependent),不同的平臺的排程機制是不同的。如果你想你的程式具有可移植性就不應該做這樣的不明智的假設。

  另外,notifyAll和notify方法沒有提供喚醒等待程式的確定順序,具體的順序是依賴JVM的,並且notifyAll所能保證的事情不超過喚醒所有的等待執行緒。這個狀況使得當你想以某種特定的順序喚醒多個執行緒時會出現問題。

  有兩種辦法達到控制執行緒的喚醒順序:

  1、使用精確喚醒模式
  
  (Specific notification pattern)

  2、使用實現了實時規範的JVM(RTSJ,Real-Time Specification for Java)(譯者注:這其實不應該算一種好的方法,這加大了對特定JVM的依賴,打破了可移植性)

  精確喚醒模式由Tom Cargill開發,詳細說明了如何控制呼叫notify和notifyAll時的執行緒的喚醒順序。這個實現是透過對需要被一起喚醒的每個執行緒或者每一套執行緒設定一個單獨的鎖達到的。透過對特定的鎖進行釋放而達到可定義的通知順序。

  如果實現合適,那麼這種模式的執行代價是最小的。然而不可避免的要增加編碼的複雜性,但是這個複雜性可以透過你得到的控制性抵消掉,如果你需要這樣的控制,你可以考慮實現這個模式。

  RTSJ改變了某些java語義的標準行為。其中之一就是確保等待執行緒按照優先順序排序。因此當多個執行緒處於等待狀態而呼叫了notify或者notifyAll,那麼具有最高優先順序的那個將首先執行,其它的繼續等待。

  通常,這不是推薦的做法,除非是進行實時程式設計。已經有幾種不同的折衷方案使得java可以進行實時程式設計。建立RTSJ的最重要的一個原則就是及時性比執行速度更重要!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10901326/viewspace-965626/,如需轉載,請註明出處,否則將追究法律責任。

相關文章