【線程狀態】
在線程的生命周期中,它要經過 新建(New)、就緒(Runnable)、運行(Running)、阻塞(Bolcked)、死亡(Dead)總共5種狀態。
尤其在線程啟動之后,它不可能一直占着CPU運行,所以CPU需要在多個線程之間相互切換,於是線程的狀態也會多次在運行、阻塞之間切換。
【新建和就緒狀態】
新建狀態:當程序使用new關鍵字創建了一個線程之后,這個線程就處於新建狀態,此時,它和一般的java對象沒有區別,僅僅由java虛擬機為其分配內存,並初始化其成員變量值。此時的線程對象沒有表現出任何線程的動態特性,程序也不會執行線程的執行體。
就緒狀態:當線程對象調用了start()方法之后,該線程就處於就緒狀態,就緒狀態相當於"等待執行"。java虛擬機會為其創建方法調用棧和程序計數器,處於這個狀態中的線程並沒有開始運行,只是表示線程可以運行,但是進入運行狀態取決於JVM里線程調度器的調度。如下情況會進入就緒狀態;
1.調用sleep()方法到了指定的時間。
2.線程調用的阻塞式IO方法已經返回。
3.線程成功地獲得了試圖取得的同步監視器。
4.線程正在等待某個通知時,其它線程發出了一個通知。
5.處於掛起狀態的線程被調用了resume()恢復方法。
[ 注意 ]
啟動線程使用 start()方法,不是run()方法!!永遠不要調用線程對象的run()方法!!!
調用start()方法,系統會把run()方法當成線程執行體來處理。
直接調用run()方法,則run()方法會立即被執行,系統會把線程對象當成一個普通對象來處理,run()方法也變成了一個普通的方法。
另外,直接調用線程對象的run()方法,則run()方法內不能通過getName()來獲得當前執行線程的名字,而是需要使用Thread.currentThread先獲得當前線程,再調用線程的getName()方法來獲得線程的名字。
另外,調用了線程的run()方法之后,該線程已經不再處於新建狀態,不要再次調用線程對象的start()方法,只能對處於新建狀態的線程調用start()方法,否則會引發IllegalThreadStateException異常。
[ 小技巧 ]
如果希望某一線程對象在調用了start()方法后立即執行,可以使用Thread.sleep(1)讓當前執行的其它線程(如主線程)睡眠1毫秒,在這1毫秒內,CPU不會空閑,它會立即去執行處於就緒狀態的線程,這樣就可以讓某一線程立即開始執行。
【運行和阻塞狀態】
運行狀態:處於就緒狀態的線程獲得了CPU的執行權,開始執行run()方法的線程執行體,則該線程處於運行狀態。
阻塞狀態:發生以下幾種情況,線程會進入阻塞狀態:
1.線程調用了sleep()方法,主動放棄所占用的系統資源。
2.線程調用了一個阻塞式IO方法,在該方法返回之前,該線程被阻塞。
3.線程試圖獲得一個同步同步監視器,但該同步監視器被其它線程所持有。
4.線程正在等待某個通知(notify或notifyAll)。
5.程序調用了線程的suspend()方法將該線程掛起,但該方法會導致死鎖,要避免使用。
[ 關於搶占式策略 ]
當一個線程開始運行之后,它不會一直處於運行狀態,線程在運行過程中需要被中斷,目的是使其它的線程獲得執行機會,線程調度的細節取決於底層所用策略。對於采用搶占式策略的系統而言,系統會給每個可執行的線程一個小時間段來處理任務,當該時間段用完之后,系統會讓該線程進入就緒狀態,讓所有線程搶占接下來的執行機會,當然,系統會考慮線程的優先級。
當前正在執行的線程被阻塞之后,其它線程也可以獲得執行機會,被阻塞的狀態在合適的時候也會進入就緒狀態(注意是就緒狀態,NOT執行狀態),即被阻塞線程的阻塞解除后,必須重新等待線程調度器再次調度它。
阻塞——>就緒——>運行
[ 線程狀態轉換圖 ]

從圖中可以看出,線程從阻塞狀態只能進入就緒狀態,無法直接進入運行狀態。
而就緒狀態和運行狀態之間的轉換通常不受程序控制,而是由系統線程調度所決定,處於就緒狀態的線程后的處理器的執行權后,線程進入運行狀態。
當處於運行狀態的線程失去處理器資源時,該線程進入就緒狀態,有一個方法例外,即yield()方法可以讓運行狀態直接轉入就緒狀態。
【線程死亡】
線程在三種情況下會進入死亡狀態:
1.run()方法或call()方法執行結束后,線程正常結束死亡。
2.線程拋出一個未捕獲的Exception或Error。
3.直接調用該線程的stop()方法來結束該線程,但是stop()方法容易導致死鎖,最好不要用。
[ 提示 ]
測試某個線程是否已經死亡,可以調用對象的isAlive()方法,
當線程處於就緒、運行、阻塞三種狀態時,返回true。
當線程處於新建、死亡狀態時,返回false。
[ 注意 ]
不要試圖對一個已經死亡的線程調用start()方法使它重啟,死亡就是死亡,該線程不可再次作為線程執行,否則會拋出IllegalThreadStateException異常,
對新建狀態的線程兩次調用start()方法也是錯誤的額,都會引發IllegalThreadStateException異常。
