Java多線程 - 線程的生命週期

Java多線程 - 線程的生命週期

引言:
Java線程被創建之後,並非是一啓動就開始執行,也不是一直處於執行狀態。
在線程的生命週期中,需要經過新建、就緒、運行、阻塞和死亡五種狀態。
線程啓動後,不可能一直佔用着CPU獨自運行,CPU需要再多條線程之間切換,於是線程狀態也會多次在運行和就緒之間切換。

一、新建和就緒狀態

當程序使用new關鍵字創建了一個線程之後,這個線程就會一直處於新建狀態,此時它和Java對象一樣,僅僅由Java虛擬機爲其分配內存,並且初始化其成員變量的值,此時線程對象沒有任何線程的動態特徵,程序也不會執行線程的線程執行體。
當線程對象調用了start()方法之後,該線程就會處於就緒狀態,Java虛擬機會爲其創建方法調用棧和程序計數器。處於這個狀態的線程並沒有開始運行,只是表示該線程可以運行了,至於該線程何時開始運行,這個取決於JVM裏線程調度器的調度

注意:啓動線程需要使用的是start()方法,而不是run()方法,永遠不許調用線程對象的run()方法!
原因: 調用start()方法,來啓動線程,會把該run()方法當成線程執行體來處理,但是如果說你要是直接調用了線程對象的run()方法,則run()方法立即就會別自行,而且,在run()方法之前的其他線程無法併發執行。也就是說:如果直接調用線程對象的run()方法,系統會把線程對象當做一個普通對象來進行處理,且run()方法也只是一個普通的方法了,並非是一個線程執行體。

class demo {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        thread1.run();

        MyThread thread2 = new MyThread();
        thread2.start();
    }
}

class MyThread extends Thread{

    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}

/*
運行結果:
main
Thread-1
由此可知,如果調用run方法,則知識當成一個普通的方法運行,其線程是main線程
 */

注意:只能對處於新建狀態的線程調用start()方法,否則將會引起異常IllegalThreadStateException

小知識: 如果你想讓你創建的進程立刻開始運行,你可以使用Thread.sleep(1)來讓當前運行的線程(主線程)睡眠1ms,1ms足夠了,因爲在這1ms內CPU並不會空閒,它回去執行另一個處於就緒狀態的線程,這樣子線程就開始立即執行。

二、運行和阻塞狀態

如果處於就緒狀態的線程獲得了CPU, 開始執行run()方法的線程執行體,則該線程處於運行狀態,如果說,計算機只有一個CPU,那麼在任何時刻只有一個線程處於運行狀態,當然,如果是一個多處理器的機器上,將會有多個線程並行,(注意:並行:同一時刻,有多條指令在多個處理器上同時執行。)當然,當線程數大於處理器數時,依然會有多個線程在同一CPU上輪換的現象。

當一個線程開始運行之後,不存在一直處於運行狀態(當然,如果說線程執行體太短,瞬間完成, 那當我沒說),線程在運行的過程中需要被中斷,目的是爲了使得別的線程獲得一個執行的機會,線程調度的具體細節取決於底層平臺所採用的的側率。

目前,現代桌面和服務器操作系統均採用搶佔式調度策略,但是有一些小型設備如同手機,可能採用協作式調度策略。

線程進入阻塞狀態的可能原因:

  • 線程調用sleep()方法主動放棄所佔用的處理器資源
  • 線程調用了一個阻塞式IO方法,在該方法返回之前,該線程會一直被阻塞
  • 線程試圖獲得一個同步監視器,但是該同步監視器別的線程所擁有着
  • 線程在等待某個通知
  • 程序調用了線程的suspend()方法將該線程掛起(注意:該方法容易導致死鎖)

當線程正在被執行的時候阻塞了,其他的線程就可以獲得執行的機會,被阻塞的線程會在何時的時候重新進入就緒狀態。
針對上面導致線程進入阻塞狀態的可能原因,可以分析出,發生以下情況,則會解除上面的阻塞:

  • 調用sleep()方法的線程已經過了指定時間了
  • 線程調用的阻塞式IO方法已經返回
  • 線程成功地獲得試圖取得的同步監視器
  • 線程正在等待某個通知時,其他線程發出了一個通知
  • 處於掛起狀態的線程調用了resume()修復方法

三、線程死亡

線程也會執行結束,當它執行結束的之後,就會處於死亡狀態。
線程會以如下的方式結束:

  • run()call()方法執行完成,線程正常結束
  • 線程跑出一個未捕獲的Exception或者Error
  • 直接調用該線程的stop()方法來結束該線程 – 該方法容易導致死鎖,不推薦使用

注意:

  • 當主線程結束的時候,其他的線程不會受到任何影響,且不會隨之結束,一旦子線程啓動起來之後,他就會有與主線程一樣的地位,不會受到主線程的影響
  • 不要試圖對一個已經死亡的線程調用start()方法使它重新啓動,死亡就是死亡了,就像戀愛被甩了,你還打算舔狗複合?!該線程已經不可以再次作爲線程執行。不僅不要對死亡狀態的線程調用start()方法,且程序只能夠對新建的線程調用start()方法,當然,對新建狀態的線程調用兩次start()方法也是錯誤的,會引發IllegalThreadState異常。
  • 判斷線程死亡:可以調用線程對象的isAlive()方法,當線程處於就緒,運行,阻塞三種狀態的時候,返回true,如果處於新建和死亡兩種狀態,該方法就會返回false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章