Java多線程(線程生命週期)

當線程被創建並啓動後,並不是一啓動就進入了執行狀態,也不是一直處於執行狀態,在線程的生命週期中,它要經歷新建、就緒、運行、阻塞和死亡5種狀態。尤其是當線程啓動以後,它不可能一直佔用CPU獨自運行,所以CPU需要在多條線程之間切換,於是線程狀態也會在運行、阻塞之間切換。

  • 新建:使用new關鍵字創建一個線程後,該線程處於新建狀態,與普通對象一樣,jvm爲其分配內存並初始化成員變量。
  • 就緒:當線程對象調用了start()方法之後,該線程處於就緒狀態,jvm會爲這個線程對象創建方法調用棧和程序計數器,這個狀態表示程序已經可以運行了。至於什麼時候開始運行,則取決於jvm裏的線程調度器的調度。
  • 運行:如果處於就緒狀態的線程獲得了CPU,開始執行run方法的線程執行體,則該線程就處於運行狀態。(

        當一個線程開始運行後,它不可能一直處於運行狀態,線程在運行過程中需要被中斷,目的是使其他線程獲得執行的機會,線程調度的細節取決於底層平臺所採用的策略。對於採用搶佔式策略的系統而言,系統會給每個可執行的線程一個小時間段來處理任務,當時間段用完後,系統就會剝奪該線程所佔用的資源,讓其他線程獲得執行的機會。在選擇下一個線程時,系統會考慮線程的優先級。

        所有的桌面、服務器系統都採用搶佔式調度策略,但一些小型設備比如手機則可能採用協作式調度策略,在這樣的系統中,只有當一個線程調用了它的sleep()或者yield()方法後纔會放棄所佔用的資源,也就是必須由該線程主動放棄所佔用的資源。

  • 阻塞:線程發生阻塞狀態時的情況:(
  1. 線程調用sleep()方法主動放棄所佔用的處理器資源。
  2. 線程調用了一個阻塞式IO方法,在該方法返回之前,該線程被阻塞。
  3. 線程試圖獲得一個同步監視器,但該同步監視器正被其他線程所持有。關於同步監視器的知識,後面會進行講解。
  4. 線程在等待某個通知(notify)
  5. 程序調用了線程的suspend()方法將該線程掛起。但這個方法容易導致死鎖,所以應該儘量避免使用該方法。)

    當前正在執行的線程被阻塞後,其他線程就可以獲得執行的機會。被阻塞的線程會在合適的時候重新進入就緒狀態,合適的時候就是指線程的阻塞解除後,會重新進入就緒狀態,等待線程調度器的再次調度。在發生如下特定情況下,可以解除線程的阻塞狀態,讓線程重新進入就緒狀態:(

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

    線程狀態轉換圖:

    從上圖中可以看出,線程從阻塞狀態只能進入就緒狀態,無法直接進入運行狀態。而就緒和運行狀態之間的轉換通常不受程序控制,而是由系統線程調度所決定,當處於就緒狀態的線程獲得處理器資源時,該線程就進入運行狀態,當處於運行狀態的線程失去處理器資源時,該線程就進入就緒狀態。如果線程調用了yield()方法,即線程讓步則線程狀態進入就緒狀態。

  • 死亡:線程會在此3種方法下進行結束,結束後就處於死亡狀態:(
  1. run()或call()方法執行完成,線程正常結束
  2. 線程拋出一個未捕獲的Exception或者直接Error錯誤。
  3. 直接調用該線程的stop()方法來結束該線程——該方法容易導致死鎖,通常不推薦使用。)(測試某個線程是否死亡,可以調用線程對象的isAlive()方法,當線程處於就緒、運行、阻塞3中狀態時,該方法將返回true;當線程處於新建、死亡2種狀態時返回false。)

注意:當主線程結束時,其他線程不受任何影響,並不會隨之結束。一旦子線程啓動之後,它就擁有和主線程相同的地位。

注意:不要試圖對一個已經死亡的線程調用start()方法使它重新啓動,程序只能對新建狀態的線程調用start()方法,死亡就是死亡,該線程不可以再次作爲線程執行。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章