摘要:服務器
當線程被建立並啓動之後,它既不是一啓動就進入了執行狀態,也不是一直處於執行狀態。在線程的生命週期中,它要通過新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態。尤爲是當線程啓動之後,它不可能一直"霸佔"着CPU獨自運行,因此CPU須要在多條線程之間切換,因而線程狀態也會屢次在運行、阻塞之間切換併發
1. 新建狀態,當程序使用new關鍵字建立了一個線程以後,該線程就處於新建狀態,此時僅由JVM爲其分配內存,並初始化其成員變量的值測試
2. 就緒狀態,當線程對象調用了start()方法以後,該線程處於就緒狀態。Java虛擬機會爲其建立方法調用棧和程序計數器,等待調度運行spa
3. 運行狀態,若是處於就緒狀態的線程得到了CPU,開始執行run()方法的線程執行體,則該線程處於運行狀態操作系統
4. 阻塞狀態,當處於運行狀態的線程失去所佔用資源以後,便進入阻塞狀態線程
5. 在線程的生命週期當中,線程的各類狀態的轉換過程設計
當程序使用new關鍵字建立了一個線程以後,該線程就處於新建狀態,此時它和其餘的Java對象同樣,僅僅由Java虛擬機爲其分配內存,並初始化其成員變量的值。此時的線程對象沒有表現出任何線程的動態特徵,程序也不會執行線程的線程執行體。對象
當線程對象調用了start()方法以後,該線程處於就緒狀態。Java虛擬機會爲其建立方法調用棧和程序計數器,處於這個狀態中的線程並無開始運行,只是表示該線程能夠運行了。至於該線程什麼時候開始運行,取決於JVM裏線程調度器的調度。blog
調用線程對象的start()方法以後,該線程當即進入就緒狀態——就緒狀態至關於"等待執行",但該線程並未真正進入運行狀態。若是但願調用子線程的start()方法後子線程當即開始執行,程序可使用Thread.sleep(1) 來讓當前運行的線程(主線程)睡眠1毫秒,1毫秒就夠了,由於在這1毫秒內CPU不會空閒,它會去執行另外一個處於就緒狀態的線程,這樣就可讓子線程當即開始執行。生命週期
若是處於就緒狀態的線程得到了CPU,開始執行run()方法的線程執行體,則該線程處於運行狀態,若是計算機只有一個CPU。那麼在任什麼時候刻只有一個線程處於運行狀態,固然在一個多處理器的機器上,將會有多個線程並行執行;當線程數大於處理器數時,依然會存在多個線程在同一個CPU上輪換的現象。
當一個線程開始運行後,它不可能一直處於運行狀態(除非它的線程執行體足夠短,瞬間就執行結束了)。線程在運行過程當中須要被中斷,目的是使其餘線程得到執行的機會,線程調度的細節取決於底層平臺所採用的策略。對於採用搶佔式策略的系統而言,系統會給每一個可執行的線程一個小時間段來處理任務;當該時間段用完後,系統就會剝奪該線程所佔用的資源,讓其餘線程得到執行的機會。在選擇下一個線程時,系統會考慮線程的優先級。
全部現代的桌面和服務器操做系統都採用搶佔式調度策略,但一些小型設備如手機則可能採用協做式調度策略,在這樣的系統中,只有當一個線程調用了它的sleep()或yield()方法後纔會放棄所佔用的資源——也就是必須由該線程主動放棄所佔用的資源。
當發生以下狀況時,線程將會進入阻塞狀態
① 線程調用sleep()方法主動放棄所佔用的處理器資源
② 線程調用了一個阻塞式IO方法,在該方法返回以前,該線程被阻塞
③ 線程試圖得到一個同步監視器,但該同步監視器正被其餘線程所持有。關於同步監視器的知識、後面將存更深刻的介紹
④ 線程在等待某個通知(notify)
⑤ 程序調用了線程的suspend()方法將該線程掛起。但這個方法容易致使死鎖,因此應該儘可能避免使用該方法
當前正在執行的線程被阻塞以後,其餘線程就能夠得到執行的機會。被阻塞的線程會在合適的時候從新進入就緒狀態,注意是就緒狀態而不是運行狀態。也就是說,被阻塞線程的阻塞解除後,必須從新等待線程調度器再次調度它。
針對上面幾種狀況,當發生以下特定的狀況時能夠解除上面的阻塞,讓該線程從新進入就緒狀態:
① 調用sleep()方法的線程通過了指定時間。
② 線程調用的阻塞式IO方法已經返回。
③ 線程成功地得到了試圖取得的同步監視器。
④ 線程正在等待某個通知時,其餘線程發出了個通知。
⑤ 處於掛起狀態的線程被調甩了resdme()恢復方法。
圖 2.1 線程狀態轉換圖
從圖2.1中能夠看出,線程從阻塞狀態只能進入就緒狀態,沒法直接進入運行狀態。而就緒和運行狀態之間的轉換一般不受程序控制,而是由系統線程調度所決定。當處於就緒狀態的線程得到處理器資源時,該線程進入運行狀態;當處於運行狀態的線程失去處理器資源時,該線程進入就緒狀態。但有一個方法例外,調用yield()方法可讓運行狀態的線程轉入就緒狀態。關於yield()方法後面有更詳細的介紐。
線程會以以下3種方式結束,結束後就處於死亡狀態:
① run()或call()方法執行完成,線程正常結束。
② 線程拋出一個未捕獲的Exception或Error。
③ 直接調用該線程stop()方法來結束該線程——該方法容易致使死鎖,一般不推薦使用。
當主線程結束時,其餘線程不受任何影響,並不會隨之結束。一旦子線程啓動起來後,它就擁有和主線程相同的地位,它不會受主線程的影響。爲了測試某個線程是否已經死亡,能夠調用線程對象的isAlivc()方法,當線程處於就緒、運行、阻塞了種狀態時,該方法將返回true;當線程處於新建、死亡狀態時,該方法將返回false。
下面程序嘗試對處於死亡狀態的線程再次調用start()。
main 0 main 1 main 2 main 3 main 4 main 5 main 6 main 7 main 8 main 9 main 10 |
main 11 main 12 main 13 main 14 main 15 main 16 main 17 main 18 main 19 main 20 true |
main 21 ………… Thread-0 0 Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 5 Thread-0 6 Thread-0 7 Thread-0 8 |
……………… Thread-0 92 Thread-0 93 Thread-0 94 Thread-0 95 Thread-0 96 Thread-0 97 Thread-0 98 Thread-0 99 main 25 Exception |
main→主線程 Thread-0→線程1 Exception→異常 |
上面程序中的粗體字代碼試圖在線程已死亡的狀況下再次調用start()方法來啓動該線程。運行上面程序,將引起IllegaIThreadStateException異常,這代表處於死亡狀態的線程沒法再次運行了。
若是,您認爲閱讀這篇博客讓您有些收穫,不妨點擊一下右下角的【推薦】。
若是,您但願更容易地發現個人新博客,不妨點擊一下左下角的【關注我】。
若是,您對個人博客所講述的內容有興趣,請繼續關注個人後續博客,我是【Sunddenly】。本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利