前提介紹
本章主要介紹相關執行緒宣告週期的轉換機制以及宣告週期的流轉關係以及相關AQS的實現和相關的基本原理,配合這相關官方文件的中英文互譯的介紹。
執行緒狀態流轉及生命週期
當執行緒被建立並啟動以後,它既不是一啟動就進入了執行狀態,也不是一直處於執行狀態。線上程的生命週期中,它要經過新建(New)、就緒/可執行狀態(Runnable)、阻塞(Blocked)和等待(Wait)、時間等待(Time_wait)、終止狀態(Terminate)六種狀態。尤其是當執行緒啟動以後,它不能一直“霸佔”著CPU獨自執行,所以CPU需要在多條執行緒之間切換,於是執行緒狀態也會多次在執行、阻塞之間切換。
下圖借鑑於官方網站:
生命週期的六種狀態
一個事物從出生的那一刻開始到最終死亡中間的整個過程.在事物的漫長的生命週期過程中,總會經歷不同的狀態(嬰兒狀態/青少年狀態/中年狀態/老年狀態...).執行緒也是有生命週期的,也是存在不同的狀態的,狀態相互之間的轉換。
執行緒物件的狀態存放在Thread類的內部類(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類其實是一個列舉類.因為執行緒物件的狀態是固定的,只有6種,此時使用列舉來表示是。
新建(new Thread)
當建立Thread類的一個例項(物件)時,此執行緒進入新建狀態(未被啟動)。
使用new建立一個執行緒物件,僅僅在堆中分配記憶體空間,在呼叫start方法之前。 新建狀態下,執行緒壓根就沒有啟動,僅僅只是存在一個執行緒物件而已.Thread t = new Thread();
此時t就屬於新建狀態當新建狀態下的執行緒物件呼叫了start方法,此時從新建狀態進入可執行狀態.執行緒物件的start方法只能呼叫一次,否則報錯:IllegalThreadStateException.
例如
Thread t1=new Thread();
可執行(runnable)
分成兩種子狀態,ready和running。分別表示就緒狀態和執行狀態。
就緒狀態
執行緒物件呼叫start方法之後,等待JVM的排程(此時該執行緒並沒有執行),這時候執行緒處於等待CPU分配資源階段,誰先搶的CPU資源,誰開始執行,換句話說執行緒已經被啟動,正在等待被分配給CPU時間片,也就是說此時執行緒正在就緒佇列中排隊等候得到CPU資源。
執行狀態
執行緒物件獲得JVM排程,如果存在多個CPU,那麼允許多個執行緒並行執行
被轉換成Terminated狀態,比如呼叫 stop() 方法;
被轉換成Blocked狀態,比如呼叫了sleep, wait 方法被加入 waitSet 中;
被轉換成Blocked狀態,如進行 IO 阻塞操作,如查詢資料庫進入阻塞狀態;
被轉換成Blocked狀態,比如獲取某個鎖的釋放,而被加入該鎖的阻塞佇列中;
該執行緒的時間片用完,CPU 再次排程,進入Runnable狀態;
執行緒主動呼叫 yield 方法,讓出 CPU 資源,進入Runnable狀態
例如
t1.start();
執行(running)他也從屬於Runnable狀態,但不在總體狀態之內,屬於邏輯狀態機制
當就緒的執行緒被排程並獲得CPU資源時,便進入執行狀態,run方法定義了執行緒的操作和功能,此時除非此執行緒自動放棄CPU資源或者有優先順序更高的執行緒進入,執行緒將一直執行到結束。
注意:
Runnable狀態的執行緒無法直接進入Blocked狀態和Terminated狀態的。只有處在Running狀態的執行緒,換句話說,只有獲得CPU排程執行權的執行緒才有資格進入Blocked狀態和Terminated狀態,Runnable狀態的執行緒要麼能被轉換成Running狀態,要麼被意外終止。
堵塞(blocked)
正在執行的執行緒因為某些原因放棄CPU,暫時停止執行,就會進入阻塞狀態.此時JVM不會給執行緒分配CPU,直到執行緒重新進入就緒狀態,才有機會轉到執行狀態.阻塞狀態只能先進入就緒狀態,不能直接進入執行狀態。
阻塞狀態的兩種情況:
- 當A執行緒處於執行過程時,試圖獲取同步鎖時,卻被B執行緒獲取.此時JVM把當前A執行緒存到物件的鎖池中,A執行緒進入阻塞狀態.
- 當執行緒處於執行過程時,發出了IO請求時,此時進入阻塞狀態.
由於某種原因導致正在執行的執行緒讓出CPU並暫停自己的執行,即進入堵塞狀態。
被轉換成Terminated狀態,比如呼叫 stop() 方法,或者是 JVM 意外 Crash;
被轉換成Runnable狀態,阻塞時間結束,比如讀取到了資料庫的資料後;
完成了指定時間的休眠,進入到Runnable狀態;
正在wait中的執行緒,被其他執行緒呼叫notify/notifyAll方法喚醒,進入到Runnable狀態;
執行緒獲取到了想要的鎖資源,進入Runnable狀態;
執行緒在阻塞狀態下被打斷,如其他執行緒呼叫了interrupt方法,進入到Runnable狀態;
等待狀態(waiting)
(等待狀態只能被其他執行緒喚醒):
此時使用的無引數的wait方法,
- 當執行緒處於執行過程時,呼叫了wait()方法,此時JVM把當前執行緒存在物件等待池中.
計時等待狀態(timed waiting)
(使用了帶引數的wait方法或者sleep方法)
- 當執行緒處於執行過程時,呼叫了wait(long time)方法,此時JVM把當前執行緒存在物件等待池中.
- :當前執行緒執行了sleep(long time)方法.
終止狀態(terminated)
通常稱為死亡狀態,表示執行緒終止.
- 正常執行完run方法而退出(正常死亡).
- 遇到異常而退出(出現異常之後,程式就會中斷)(意外死亡).
- JVM 異常結束,所有的執行緒生命週期均被結束。
執行緒一旦終止,就不能再重啟啟動,否則報錯(IllegalThreadStateException).
不推薦使用的執行緒方法
在Thread類中過時的方法(因為存線上程安全問題,所以棄用了):
- void suspend() :暫停當前執行緒
- void resume() :恢復當前執行緒
- void stop() :結束當前執行緒
給大家結合官網在進行一箇中文解釋的狀態流轉圖: