java執行緒的狀態變換
下面將會針這張圖對執行緒的狀態轉換來做解釋
在作業系統的課程中把執行緒大致分為了3個狀態
1.就緒狀態(執行緒對資源上鎖,但未分配時間片,等待cpu分配,隨時可以執行)
2.執行狀態(執行緒對資源上鎖,並擁有了時間片,正在執行中)
3.阻塞狀態(在執行狀態下缺失了某種資源導致執行暫停,也可以是被cpu強制暫停)
java中多了新建和死亡狀態,新建狀態(new)就是執行緒定義好了之後,還沒呼叫start方法告訴作業系統。死亡狀態就是run方法執行完,也就是執行緒操作完畢。這兩個狀態很容易理解。
就緒----->執行很簡單,分配時間片就行,這個不需要我們擔心,
執行----->就緒就不簡單了,因為中間可能存在阻塞態
(1)執行----->就緒
這個狀態變換是由於執行緒失去時間片,可以使用.yield()實現
使用yield()後執行緒短暫停,暫停由系統決定的毫秒級時間,執行緒不釋放鎖,僅剝奪時間片,所以執行緒暫停結束後進入就緒狀態
(2)執行----->阻塞------>就緒
1)不釋放鎖的阻塞
包括sleep,join方法
sleep()方法
我們看到sleep()方法描述暫停一定時間後恢復就緒狀態,不釋放鎖,時間結束後進入就緒狀態。跟yield很像,那為什麼sleep算阻塞呢,原因是sleep()的暫停時間是系統和使用者一起決定的,使用者可以設定休眠很長時間,比如一分鐘,我們知道執行緒的執行都是毫秒級別的,這樣一比sleep自然就屬於了阻塞。
join()
這個方法讓呼叫該方法的執行緒優先執行,通常設定在另一個執行緒的run()方法中
class Father extends Thread{ public void run() { Thread son=new Son(); son.start(); try { son.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class Son extends Thread{ public void run() { } }
在上面的程式碼中我們希望Son先執行,我們可以在Father中實現son.join()來讓
son插隊到Father執行緒的前面執行,那麼對Father來說,就相當於被插隊,此時阻塞,當插隊的son執行完後Father並不立即執行,而是回到就緒狀態,等待cpu時間片
需要注意的是,作業系統控制的執行緒遇到類似I/O操作這類等待臨界資源導致的阻塞也是不釋放鎖的阻塞,在拿到臨界資源的鎖後就緒,隨時可以執行,但這也使得多個執行緒佔據不同的鎖,容易引起死鎖
(2)釋放鎖的阻塞
wait()和wait(long ,int)
wait()方法使執行緒失去時間片,失去鎖,並被冷藏,直到使用notify()/notifyAll()喚醒
notify()喚醒單個執行緒,notifyAll()喚醒所有
wait(long,int)和上面基本一樣,唯一不同的是這裡可以設定一個引數為時間,在notify()喚醒前如果時間耗盡會自動甦醒,不必等notify
另外,interrupt()也可以用在這裡改變執行緒狀態
喚醒後的執行緒依然是阻塞狀態,和喚醒前不同的是執行緒可以去爭奪資源鎖,此時就類似遇到同步鎖而被動阻塞執行緒,在獲取了所有鎖之後就進入就緒狀態,隨時可以執行。