線程的生命週期?什麼時候會出現僵死進程?

線程的生命週期及五種基本狀態

關於Java中線程的生命週期,首先看一下下面這張較爲經典的圖:

線程生命週期

  • 新建(new Thread)

當創建Thread類的一個實例(對象)時,此線程進入新建狀態(未被啓動)。例如:Thread t1=new Thread();

  • 就緒(runnable)

調用Thread類的start方法,線程已經被啓動,進入就緒狀態,正在等待被分配給CPU時間片,也就是說此時線程正在就緒隊列中排隊等候得到CPU資源。

  • 運行(running)

線程獲得CPU資源正在執行任務(執行run()方法),此時除非此線程自動放棄CPU資源或者有優先級更高的線程進入,線程將一直運行到結束或者時間片結束。

  • 堵塞(blocked)

由於某種原因導致正在運行的線程讓出CPU並暫停自己的執行,即進入堵塞狀態。阻塞結束後線程進入就緒狀態。
堵塞的情況分三種:

(一)等待堵塞:執行的線程執行wait()方法,JVM會把該線程放入等待池中。

(二)同步堵塞:執行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用。則JVM會把該線程放入鎖池中。

(三)其它堵塞:執行的線程執行sleep()或join()方法,或者發出了I/O請求時。JVM會把該線程置爲堵塞狀態。
當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完成時。線程又一次轉入就緒狀態。

  • 死亡(dead)

    當線程執行完畢(run方法運行結束)或被其它線程殺死,線程就進入死亡狀態,這時線程不可能再進入就緒狀態等待執行。

線程間的狀態轉換

鏈接url
線程間的狀態轉換

  • 解釋:

    1、線程的實現有兩種方式,一是繼承Thread類,二是實現Runnable接口,但無論如何,當我們new了這個對象後。線程就進入了初始狀態;
    2、當該對象調用了start()方法,就進入可執行狀態; 3、進入可執行狀態後,當該對象被操作系統選中。獲得CPU時間片就會進入執行狀態;
    4、進入執行狀態後情況就比較複雜了
    4.1、run()方法或main()方法結束後,線程就進入終止狀態;
    4.2、當線程調用了自身的sleep()方法或其它線程的join()方法,就會進入堵塞狀態(該狀態既停止當前線程,但並不釋放所佔有的資源)。當sleep()結束或join()結束後。該線程進入可執行狀態,繼續等待OS分配時間片;
    4.3、線程調用了yield()方法,意思是放棄當前獲得的CPU時間片,回到可執行狀態,這時與其它進程處於同等競爭狀態,OS有可能會接着又讓這個進程進入執行狀態。

    4.4、當線程剛進入可執行狀態(注意,還沒執行),發現將要調用的資源被synchroniza(同步),獲取不到鎖標記。將會馬上進入鎖池狀態,等待獲取鎖標記(這時的鎖池裏或許已經有了其它線程在等待獲取鎖標記,這時它們處於隊列狀態,既先到先得),一旦線程獲得鎖標記後,就轉入可執行狀態。等待OS分配CPU時間片。

    4.5、當線程調用wait()方法後會進入等待隊列(進入這個狀態會釋放所佔有的全部資源,與堵塞狀態不同)。進入這個狀態後。是不能自己主動喚醒的,必須依靠其它線程調用notify()或notifyAll()方法才幹被喚醒(因爲notify()僅僅是喚醒一個線程,但我們由不能確定詳細喚醒的是哪一個線程。或許我們須要喚醒的線程不可以被喚醒,因此在實際使用時,一般都用notifyAll()方法,喚醒有所線程),線程被喚醒後會進入鎖池。等待獲取鎖標記。

一個線程會因爲以下原因而放棄CPU:

  1. 時間片用完了,java虛擬機讓當前線程暫時放棄CPU,轉到就緒狀態,使其它線程獲得運行機會。

  2. 當前線程因爲某些原因而進入阻塞狀態

  3. 線程結束運行

線程在以下情況會停止:

  1. run方法正常執行完畢

  2. run方法執行過程中拋出一個未捕獲的異常

  3. 調用stop方法(不推薦使用)

進程的停止,當一個進程中所有的前臺線程停止後,該進程結束。

如果希望明確地讓一個線程給另外一個線程運行的機會,可以採取以下辦法。
1. 調整各個線程的優先級
2. 讓處於運行狀態的線程調用Thread.sleep()方法
3. 讓處於運行狀態的線程調用Thread.yield()方法
4. 讓處於運行狀態的線程調用另一個線程的join()方法

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