Java線程的生命周期可以分為五個狀態(tài),分別是新建(New)、就緒(Runnable)、運(yùn)行(Running)、阻塞(Blocked)和終止(Terminated)。
線程狀態(tài)的轉(zhuǎn)換如下:
新建(New)狀態(tài)
在新建線程對象后,該線程對象還沒有被分配 CPU 時間片,不會執(zhí)行任何代碼。此時線程對象處于 New 狀態(tài)。
線程對象處于 New 狀態(tài)時,它的狀態(tài)可以改變,例如可以調(diào)用 start() 方法啟動線程,使其進(jìn)入就緒狀態(tài),也可以在新建線程對象時通過調(diào)用 setPriority() 方法設(shè)置線程的優(yōu)先級,或者通過調(diào)用 setName() 方法設(shè)置線程的名稱等等。
就緒(Runnable)狀態(tài)
當(dāng)線程調(diào)用了 start() 方法后,線程對象進(jìn)入就緒狀態(tài),此時它已經(jīng)分配了 CPU 時間片,并等待系統(tǒng)分配 CPU 時間片開始執(zhí)行線程代碼。處于就緒狀態(tài)的線程不一定能立即得到 CPU 時間片,它們處于等待狀態(tài),直到系統(tǒng)分配到它們所需要的 CPU 時間片。
處于就緒狀態(tài)的線程通過調(diào)度器來決定哪個線程獲得 CPU 時間片,線程調(diào)度器的調(diào)度算法通常是先進(jìn)先出(FIFO)。
運(yùn)行(Running)狀態(tài)
當(dāng)線程獲得了 CPU 時間片后,進(jìn)入運(yùn)行狀態(tài),此時線程開始真正執(zhí)行線程代碼。線程代碼中的指令依次執(zhí)行,直到程序執(zhí)行完畢或者執(zhí)行到 sleep()、wait() 等方法時,線程會進(jìn)入阻塞狀態(tài),直到阻塞條件被解除。
在運(yùn)行狀態(tài)下,線程可以執(zhí)行一些耗時操作,例如計算、循環(huán)等等。當(dāng)線程被分配到的 CPU 時間片用完后,系統(tǒng)會將其轉(zhuǎn)為就緒狀態(tài),等待下一次分配 CPU 時間片。
阻塞(Blocked)狀態(tài)
線程在運(yùn)行時可能會遇到一些阻塞條件,例如等待 I/O、sleep 等操作。當(dāng)線程執(zhí)行這些操作時,線程會進(jìn)入阻塞狀態(tài),它會暫停執(zhí)行并且釋放 CPU 時間片,直到阻塞條件被解除。
在阻塞狀態(tài)下,線程不能執(zhí)行任何代碼,直到阻塞條件被解除時,線程才會轉(zhuǎn)為就緒狀態(tài),等待系統(tǒng)分配 CPU 時間片。
終止(Terminated)狀態(tài)
線程可能因為兩個原因進(jìn)入終止?fàn)顟B(tài):(1)線程正常執(zhí)行完畢,或者(2)線程出現(xiàn)了未捕獲的異常而意外終止。
線程進(jìn)入終止?fàn)顟B(tài)后,它會釋放所有的資源,并且不能再運(yùn)行任何代碼。一旦線程進(jìn)入了終止?fàn)顟B(tài),就不可能再回到運(yùn)行狀態(tài)或阻塞狀態(tài)了。
例如,可以通過調(diào)用 Thread 類的 join() 方法,讓主線程等待子線程執(zhí)行完畢后再終止,以保證線程能夠正常退出。