執行緒的幾種狀態
目錄
此節主要看以下執行緒的狀態,通過原始碼的列舉型別,我們可以看到執行緒的六種狀態。
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;
}
執行緒狀態
此六種狀態的轉換關係如下圖所示:
1. 初始狀態-NEW
當我們通過實現Runnable介面和繼承Thread建立一個執行緒類,new一個例項出來,執行緒就進入了初始狀態。
Thread thread = new Thread(); //初始狀態;
2. 執行狀態-RUNNABLE
當被排程程式選中後,執行緒就獲取了CPU的執行許可權,獲取了CPU執行時間分片後,進行執行執行階段
ps:就緒狀態-READY
就緒狀態其實是一個不存在的狀態,但是為了好理解,我們加入了這樣一個狀態階段,就緒狀態只是說你有資格參與競爭鎖和獲取鎖,一切準備妥當,隨時等待著被呼叫執行。就緒狀態包含以下情況:
- 執行緒呼叫了start()方法;
- 當前執行緒sleep()方法結束,其他執行緒join()結束,I/O等待結束,例如使用者輸入完畢;
- 拿到某個執行緒拿到物件鎖;
- 當前執行緒時間片用完了,呼叫當前執行緒的yield()方法,當前執行緒進入就緒狀態。
3. 阻塞狀態 BLOCKED
阻塞狀態是執行緒需要執行同步程式碼塊synchronized關鍵字修飾的方法或程式碼塊,為了獲取鎖而阻塞的狀態;
4. 等待 WAITTING
此狀態的執行緒將會處於無限期的等待狀態,不會被分配CPU執行時間,直到它們被notify()/notifyAll()/LockSupport.unpark()顯式地喚醒;
5. 超時等待 TIMED_WAITTING
此狀態的執行緒不會被分配CPU執行時間,但是它們不必無限期等待被其他執行緒顯示地喚醒,在達到time_out時間達後就會自動喚醒。
6. 終止狀態 TERMINATED
當執行緒的run()方法完成時,或者主執行緒的main()方法完成時,我們就認為它終止了。執行緒一旦終止了,就不能復生。
在一個終止的執行緒上呼叫start()方法,會丟擲java.lang.IllegalThreadStateException異常。
ps:物件鎖和類鎖
這兩種鎖是不同的鎖,所以多個執行緒同時執行這2個不同鎖的方法時,是非同步的。
synchronized 加到 static 方法前面是給class 加鎖,即類鎖,對所有的例項物件都起作用;
而synchronized 加到非靜態方法前面是給物件上鎖。
方法的比較
Thread.sleep(long millis)
當前執行緒呼叫此方法,即當前執行緒會從“執行狀態”進入到“休眠(阻塞)狀態”-TIMED_WAITING狀態,但不釋放物件鎖,millis後執行緒自動甦醒進入就緒狀態。 作用:自身等待,給其它執行緒執行的機會; |
Thread.yield()
當前執行緒呼叫此方法,當前執行緒由“執行狀態”變為“就緒狀態”,當前執行緒放棄獲取的CPU時間片,但不釋放鎖資源,讓OS再次選擇執行緒。 作用:讓相同優先順序的執行緒輪流執行,但並不保證一定會輪流執行。實際中並不能保證在當前執行緒呼叫yield()之後,其它具有相同優先順序的執行緒就一定能獲得執行權;也有可能是當前執行緒又進入到“執行狀態”繼續執行。 該方法與sleep()類似,只是不能由使用者指定暫停多長時間。 |
thread.join()/thread.join(long millis)
當前執行緒裡呼叫其它執行緒t的join方法,當前執行緒由“執行狀態”變為“等待狀態”-WAITING/TIMED_WAITING狀態,當前執行緒不會釋放已經持有的物件鎖。執行緒t執行完畢或者millis時間到,當前執行緒一般情況下進入RUNNABLE狀態;因為join是基於wait實現的,如果沒有獲取到synchronized鎖,將會進入進入BLOCKED狀態。 |
obj.wait()/wait(long timeout)
當前執行緒呼叫物件的object.wait(),當前執行緒由“執行狀態”進入到“等待(阻塞)狀態”,釋放物件監視器(物件鎖)的所有權,進入等待佇列,依靠notify()/notifyAll()喚醒或者timeout時間到自動喚醒,然後同步佇列裡競爭鎖,只有同步佇列的執行緒才有資格獲取物件鎖,只有噹噹前執行緒獲取該物件監視器後才可以繼續執行。 |
obj.notify()/notifyAll()
喚醒在此物件監視器上等待的單個執行緒,由“等待佇列”進入“同步佇列”,喚醒的執行緒是任意的。notifyAll()喚醒在此物件監視器上等待的所有執行緒。 |
LockSupport.park()/LockSupport.parkNanos(long nanos)/LockSupport.parkUntil(long deadlines)
當前執行緒由“執行狀態”進入“等待狀態”-WAITING/TIMED_WAITING狀態。 LockSupport對比Object的wait/notify有兩大優勢: (1) LockSupport不需要在同步程式碼塊裡 。所以執行緒間也不需要維護一個共享的同步物件了,實現了執行緒間的解耦。 (2) unpark函式可以先於park呼叫,所以不需要擔心執行緒間的執行的先後順序。 |
問題與解答
問題1:為什麼wait和notify方法是Object類中的方法,而不是在Thread裡?
因為:執行緒與鎖是分不開的,執行緒的同步、等待、喚醒都與物件鎖是密不可分的。notify(), wait()依賴於“同步鎖”,而“同步鎖”是物件鎖持有,依賴於物件,並且每個物件有且僅有一個,這就是為什麼notify(), wait()等函式定義在Object類。
問題2:為什麼wait和notify需要配合synchronized使用?
/**
* Causes the current thread to wait until either another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object, or a
* specified amount of time has elapsed.
* <p>
* The current thread must own this object's monitor. //必須獲取物件監視器
* <p>
**/
public final native void wait(long timeout) throws InterruptedException;
通過jdk的原始碼可以發現,雖然wait()是native方法,但是註釋上有一句話:“The current thread must own this object's monitor.”,所以就是使用wait()必須擁有物件的監視器monitor,我們知道監視器是synchronized底層的實現,synchronized的底層使用了monitorenter和monitorexit指令,不進入程式碼塊是無法擁有這個物件的monitor的。所以必須配合synchronized使用。
如果wait和notify不配合synchronized使用,就會丟擲 java.lang.IllegalMonitorStateException 的異常。
問題3: Thread wait()和sleep()的區別?
所屬的類 | sleep是屬於Thread類的方法; wait()是屬於Object類的方法; |
用法 |
(1) sleep必須指定時間;(2) sleep可以在任意的地方使用; |
釋放資源 | sleep釋放cpu的執行許可權,但是不釋放物件鎖許可權; wait釋放cpu的執行權和物件鎖許可權; |
問題4: yield() 與 wait()的比較
狀態轉換 |
wait()是讓執行緒由“執行狀態”進入到“等待(阻塞)狀態”; yield()是讓執行緒由“執行狀態”進入到“就緒狀態”; |
資源釋放 |
wait()是會執行緒釋放它所持有物件的同步鎖; yield()方法不會釋放鎖。 |
參考資料
https://blog.csdn.net/WuLex/article/details/78992692
https://blog.csdn.net/pange1991/article/details/53860651
https://www.cnblogs.com/happy-coder/p/6587092.html
https://www.cnblogs.com/GooPolaris/p/8079490.html
https://blog.csdn.net/qq_32924343/article/details/79914175
https://www.cnblogs.com/qingquanzi/p/8228422.html
https://blog.csdn.net/qq_32924343/article/details/79914175
相關文章
- 執行緒的幾種狀態總結執行緒
- 執行緒池的五種狀態及建立執行緒池的幾種方式執行緒
- 【Java】執行緒的 6 種狀態Java執行緒
- Java 執行緒的5種狀態Java執行緒
- 執行緒的6種狀態以及轉變執行緒
- 執行緒狀態執行緒
- Java多執行緒-執行緒狀態Java執行緒
- Java執行緒的狀態Java執行緒
- Java的六種執行緒狀態及程式碼示例Java執行緒
- ThreadPollExcutor執行緒池的狀態thread執行緒
- 多執行緒的執行緒狀態及相關操作執行緒
- 執行緒狀態和鎖執行緒
- 併發程式設計基礎——執行緒狀態,啟動及停止的幾種方式程式設計執行緒
- java執行緒的狀態+鎖分析Java執行緒
- Java提供的幾種執行緒池Java執行緒
- 執行緒池建立的幾種方式執行緒
- Java執行緒狀態轉換Java執行緒
- MySQL執行緒狀態詳解MySql執行緒
- jstack判斷執行緒狀態JS執行緒
- java 多執行緒之使用 interrupt 停止執行緒的幾種方法Java執行緒
- java執行緒的五大狀態,阻塞狀態詳解Java執行緒
- 透徹講解,Java執行緒的6種狀態及切換Java執行緒
- 總算把執行緒六種狀態的轉換說清楚了!執行緒
- 玩轉java多執行緒 之多執行緒基礎 執行緒狀態 及執行緒停止實戰Java執行緒
- 如何使用jstack分析執行緒狀態JS執行緒
- Java執行緒狀態及切換Java執行緒
- Memcached 多執行緒和狀態機執行緒
- Java執行緒狀態及同步鎖Java執行緒
- java--執行緒池--建立執行緒池的幾種方式與執行緒池操作詳解Java執行緒
- 一起分析執行緒的狀態及執行緒通訊機制執行緒
- 執行緒的狀態轉換以及基本操作執行緒
- 【多執行緒與高併發】- 執行緒基礎與狀態執行緒
- 併發程式設計——Java執行緒的6種狀態及切換程式設計Java執行緒
- JavaSE_多執行緒入門 執行緒安全 死鎖 狀態 通訊 執行緒池Java執行緒
- 詳解Java執行緒池的ctl(執行緒池控制狀態)【原始碼分析】Java執行緒原始碼
- JAVA 執行緒狀態及轉化(轉)Java執行緒
- java的執行緒、建立執行緒的 3 種方式、靜態代理模式、Lambda表示式簡化執行緒Java執行緒模式
- c# 多執行緒的幾種方式 【轉載】C#執行緒
- Java建立多執行緒的幾種方式實現Java執行緒