前提介紹
本章主要介紹相關線程聲明周期的轉(zhuǎn)換機制以及聲明周期的流轉(zhuǎn)關系以及相關AQS的實現(xiàn)和相關的基本原理,配合這相關官方文檔的中英文互譯的介紹。
線程狀態(tài)流轉(zhuǎn)及生命周期
當線程被創(chuàng)建并啟動以后,它既不是一啟動就進入了執(zhí)行狀態(tài),也不是一直處于執(zhí)行狀態(tài)。在線程的生命周期中,它要經(jīng)過新建(New)、就緒/可運行狀態(tài)(Runnable)、阻塞(Blocked)和等待(Wait)、時間等待(Time_wait)、終止狀態(tài)(Terminate)六種狀態(tài)。尤其是當線程啟動以后,它不能一直“霸占”著CPU獨自運行,所以CPU需要在多條線程之間切換,于是線程狀態(tài)也會多次在運行、阻塞之間切換。
下圖借鑒于官方網(wǎng)站:

生命周期的六種狀態(tài)
一個事物從出生的那一刻開始到最終死亡中間的整個過程.在事物的漫長的生命周期過程中,總會經(jīng)歷不同的狀態(tài)(嬰兒狀態(tài)/青少年狀態(tài)/中年狀態(tài)/老年狀態(tài)...).線程也是有生命周期的,也是存在不同的狀態(tài)的,狀態(tài)相互之間的轉(zhuǎn)換。
線程對象的狀態(tài)存放在Thread類的內(nèi)部類(State)中:
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
注意:Thread.State類其實是一個枚舉類.因為線程對象的狀態(tài)是固定的,只有6種,此時使用枚舉來表示是。
新建(new Thread)
- 當創(chuàng)建Thread類的一個實例(對象)時,此線程進入新建狀態(tài)(未被啟動)。
- 使用new創(chuàng)建一個線程對象,僅僅在堆中分配內(nèi)存空間,在調(diào)用start方法之前。 新建狀態(tài)下,線程壓根就沒有啟動,僅僅只是存在一個線程對象而已.Thread t = new Thread();
- 此時t就屬于新建狀態(tài)當新建狀態(tài)下的線程對象調(diào)用了start方法,此時從新建狀態(tài)進入可運行狀態(tài).線程對象的start方法只能調(diào)用一次,否則報錯:IllegalThreadStateException.
例如
Thread t1=new Thread();
可運行(runnable)
分成兩種子狀態(tài),ready和running。分別表示就緒狀態(tài)和運行狀態(tài)。
就緒狀態(tài)
線程對象調(diào)用start方法之后,等待JVM的調(diào)度(此時該線程并沒有運行),這時候線程處于等待CPU分配資源階段,誰先搶的CPU資源,誰開始執(zhí)行,換句話說線程已經(jīng)被啟動,正在等待被分配給CPU時間片,也就是說此時線程正在就緒隊列中排隊等候得到CPU資源。
運行狀態(tài)
線程對象獲得JVM調(diào)度,如果存在多個CPU,那么允許多個線程并行運行
- 被轉(zhuǎn)換成Terminated狀態(tài),比如調(diào)用 stop() 方法;
- 被轉(zhuǎn)換成Blocked狀態(tài),比如調(diào)用了sleep, wait 方法被加入 waitSet 中;
- 被轉(zhuǎn)換成Blocked狀態(tài),如進行 IO 阻塞操作,如查詢數(shù)據(jù)庫進入阻塞狀態(tài);
- 被轉(zhuǎn)換成Blocked狀態(tài),比如獲取某個鎖的釋放,而被加入該鎖的阻塞隊列中;
- 該線程的時間片用完,CPU 再次調(diào)度,進入Runnable狀態(tài);
- 線程主動調(diào)用 yield 方法,讓出 CPU 資源,進入Runnable狀態(tài)
例如
t1.start();
運行(running)他也從屬于Runnable狀態(tài),但不在總體狀態(tài)之內(nèi),屬于邏輯狀態(tài)機制
當就緒的線程被調(diào)度并獲得CPU資源時,便進入運行狀態(tài),run方法定義了線程的操作和功能,此時除非此線程自動放棄CPU資源或者有優(yōu)先級更高的線程進入,線程將一直運行到結(jié)束。
[圖片上傳失敗...(image-8d4fcd-1631164223141)]
注意:
Runnable狀態(tài)的線程無法直接進入Blocked狀態(tài)和Terminated狀態(tài)的。只有處在Running狀態(tài)的線程,換句話說,只有獲得CPU調(diào)度執(zhí)行權的線程才有資格進入Blocked狀態(tài)和Terminated狀態(tài),Runnable狀態(tài)的線程要么能被轉(zhuǎn)換成Running狀態(tài),要么被意外終止。
堵塞(blocked)
正在運行的線程因為某些原因放棄CPU,暫時停止運行,就會進入阻塞狀態(tài).此時JVM不會給線程分配CPU,直到線程重新進入就緒狀態(tài),才有機會轉(zhuǎn)到運行狀態(tài).阻塞狀態(tài)只能先進入就緒狀態(tài),不能直接進入運行狀態(tài)。
阻塞狀態(tài)的兩種情況:
- 當A線程處于運行過程時,試圖獲取同步鎖時,卻被B線程獲取.此時JVM把當前A線程存到對象的鎖池中,A線程進入阻塞狀態(tài).
- 當線程處于運行過程時,發(fā)出了IO請求時,此時進入阻塞狀態(tài).
由于某種原因?qū)е抡谶\行的線程讓出CPU并暫停自己的執(zhí)行,即進入堵塞狀態(tài)。
[圖片上傳失敗...(image-1ca0eb-1631164223141)]
- 被轉(zhuǎn)換成Terminated狀態(tài),比如調(diào)用 stop() 方法,或者是 JVM 意外 Crash;
- 被轉(zhuǎn)換成Runnable狀態(tài),阻塞時間結(jié)束,比如讀取到了數(shù)據(jù)庫的數(shù)據(jù)后;
- 完成了指定時間的休眠,進入到Runnable狀態(tài);
- 正在wait中的線程,被其他線程調(diào)用notify/notifyAll方法喚醒,進入到Runnable狀態(tài);
- 線程獲取到了想要的鎖資源,進入Runnable狀態(tài);
- 線程在阻塞狀態(tài)下被打斷,如其他線程調(diào)用了interrupt方法,進入到Runnable狀態(tài);
等待狀態(tài)(waiting)
(等待狀態(tài)只能被其他線程喚醒):
此時使用的無參數(shù)的wait方法,
- 當線程處于運行過程時,調(diào)用了wait()方法,此時JVM把當前線程存在對象等待池中.
計時等待狀態(tài)(timed waiting)
(使用了帶參數(shù)的wait方法或者sleep方法)
- 當線程處于運行過程時,調(diào)用了wait(long time)方法,此時JVM把當前線程存在對象等待池中.
- :當前線程執(zhí)行了sleep(long time)方法.
終止狀態(tài)(terminated)
通常稱為死亡狀態(tài),表示線程終止.
- 正常執(zhí)行完run方法而退出(正常死亡).
- 遇到異常而退出(出現(xiàn)異常之后,程序就會中斷)(意外死亡).
- JVM 異常結(jié)束,所有的線程生命周期均被結(jié)束。
線程一旦終止,就不能再重啟啟動,否則報錯(IllegalThreadStateException).
不推薦使用的線程方法
在Thread類中過時的方法(因為存在線程安全問題,所以棄用了):
- void suspend() :暫停當前線程
- void resume() :恢復當前線程
- void stop() :結(jié)束當前線程
給大家結(jié)合官網(wǎng)在進行一個中文解釋的狀態(tài)流轉(zhuǎn)圖:
