Java 併發編程:多線程如何實現阻塞與喚醒

線程的阻塞和喚醒在多線程併發過程當中是一個關鍵點,當線程數量達到很大的數量級時,併發可能帶來不少隱蔽的問題。如何正確暫停一個線程,暫停後又如何在一個要求的時間點恢復,這些都須要仔細考慮的細節。Java爲咱們提供了多種API來對線程進行阻塞和喚醒操做,好比suspend與resume、sleep、wait與notify以及park與unpark等等。多線程

 

 

睡眠

控制線程阻塞與喚醒的最簡單方式就是sleep了,Java經過sleep(n)方法能讓線程進入到阻塞等待狀態,直到休眠時間達到指定值後自動喚醒。該方法簡單也經常使用,但這種方式比較死板,須要咱們預先肯定線程進入阻塞的時間。而有些場景實際上咱們根本沒辦法肯定睡眠時間,這是sleep方式的最大劣勢。併發

sleep的使用很簡單,下面爲一個例子。讓當前線程睡眠2000ms,最終輸出爲"Sleep time in ms = 2000"。spa

 

掛起與恢復

在Java發展史上曾經使用suspend()、resume()方法對於線程進行阻塞喚醒,它可以在代碼中控制阻塞和喚醒的時間節點,比起sleep()方法更加靈活。好比線程啓動後在某個時間點須要讓它掛起,這能夠使用suspend方法,而當要從新喚醒它時則使用resume方法。 線程

 

 

注意:suspend(),resume(),stop()這樣的方法都被標註爲過時方法,由於其不會保證釋放資源,容易產生死鎖,因此不建議使用。3d

 死鎖問題 

爲何會產生上面的現象呢?實際上是由死鎖致使。乍一看感受一點問題都沒有,線程的任務僅僅只是簡單地打印字符串。其實問題的根源隱藏得較深,主線程啓動了線程mt後,線程mt開始執行execute()方法,不斷打印字符串。對象

 

問題就出如今System.out.println,因爲println被聲明爲一個同步方法,執行時將對System類的out(PrintStream類的一個實例)單例屬性加同步鎖。而suspend()方法掛起線程但並不釋放鎖,在線程mt被掛起後主線程調用System.out.println一樣須要獲取System類ut對象的同步鎖才能打印「can you get here?」。主線程就一直在等待同步鎖而mt線程不釋放鎖,這就致使了死鎖的產生。blog

相關文章
相關標籤/搜索