【搞定Java併發程式設計】第1篇:執行緒的五種可用狀態
本文轉載自牛客網上一網友的回答:概括的解釋下執行緒的幾種可用狀態
第一種狀態:新建(new):新建了一個執行緒物件。例如,Thread thread = new Thread();
第二種狀態:可執行狀態(Runnable):又叫“就緒狀態”。執行緒新建後,其他執行緒(比如main執行緒)呼叫了該物件的start()方法,從而來啟動該執行緒。Runnable狀態的執行緒位於可執行執行緒池中,等待被執行緒排程選中,獲取CPU的使用權;
第三種狀態:執行狀態(Running):可執行狀態(Runnable)的執行緒獲得了CPU時間片(timeslice),執行程式碼。需要注意的是,執行緒只能從就緒狀態進入到執行狀態;
第四種狀態:阻塞狀態(Block):阻塞狀態是指執行緒因為某種原因放棄了CPU使用權,即讓出了CPU TimeSlice,暫時停止執行。直到執行緒重新進入可執行(Runnable)狀態,才有機會再次獲得CPU TimeSlice轉到執行(Running)狀態。阻塞的情況有三種:
1、等待阻塞:執行(Running)的執行緒執行wait()方法,JVM會把該執行緒放入等待佇列(waiting queue)中;
2、同步阻塞:執行(Running)的執行緒在獲取物件的同步鎖時,若該同步鎖被別的執行緒佔用,則JVM會把該執行緒先放入鎖池(lock pool)中;
3、其他阻塞:執行(RunnIng)的執行緒執行Thread.sleep()方法或者t.join()方法,或者發出I/O請求時,JVM會把該執行緒置為阻塞狀態。當sleep()狀態超時時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入可執行(Runnable)狀態。
第五種狀態:死亡(Dead):執行緒run()方法和main()方法執行結束、或者因異常退出了run()方法,則該執行緒結束生命週期。死亡的執行緒是不可再次重生的。
另一位牛友的比喻回答:
可以用早起坐地鐵來比喻這個過程:
還沒起床:sleeping
起床收拾好了,隨時可以坐地鐵出發:Runnable
等地鐵來:Waiting
地鐵來了,但要排隊上地鐵:I/O阻塞
上了地鐵,發現暫時沒座位:synchronized阻塞
地鐵上找到座位:Running
到達目的地:Dead
比較重要的幾點需要注意:
1 sleep和yield的區別在於, sleep可以使優先順序低的執行緒得到執行的機會, 而yield只能使同優先順序的執行緒有執行的機會;
2 interrupt方法不會中斷一個正在執行的執行緒.就是指執行緒如果正在執行的過程中, 去呼叫此方法是沒有任何反應的. 為什麼呢, 因為這個方法只是提供給 被阻塞的執行緒, 即當執行緒呼叫了.Object.wait, Thread.join, Thread.sleep三種方法之一的時候, 再呼叫interrupt方法, 才可以中斷剛才的阻塞而繼續去執行執行緒;
3 join() 當join(0)時等待一個執行緒執行直到它死亡返回主執行緒, 當join(1000)時主執行緒等待一個執行緒1000納秒,後回到主執行緒繼續執行;
4 waite()和notify()必須在synchronized函式或synchronized block中進行呼叫。如果在non-synchronized函式或non-synchronized block中進行呼叫,雖然能編譯通過,但在執行時會發生IllegalMonitorStateException的異常。
這5種狀態涉及到的內容包括Object類, Thread和synchronized關鍵字。
Object類,定義了wait(), notify(), notifyAll()等休眠/喚醒函式。
Thread類,定義了一些列的執行緒操作函式。例如,sleep()休眠函式, interrupt()中斷函式, getName()獲取執行緒名稱等。
synchronized,是關鍵字;它區分為synchronized程式碼塊和synchronized方法。synchronized的作用是讓執行緒獲取物件的同步鎖。
在後面詳細介紹wait(),notify()等方法時,我們會分析為什麼“wait(), notify()等方法要定義在Object類,而不是Thread類中”。
參考及推薦
1、牛客網:概括的解釋下執行緒的幾種可用狀態
2、Java多執行緒系列--“基礎篇”01之 基本概念:http://www.cnblogs.com/skywang12345/p/3479024.html