線程狀態概述:java
當線程被建立並啓動之後,它既不是一啓動就進入了執行狀態,也不是一直處於執行狀態。在線程的生命週期中, 有幾種狀態呢?在API中 java.lang.Thread.State 這個枚舉中給出了六種線程狀態ide
Timed Waiting(計時等待) spa
Timed Waiting在API中的描述爲:一個正在限時等待另外一個線程執行一個(喚醒)動做的線程處於這一狀態線程
在咱們寫賣票的案例中,爲了減小線程執行太快,現象不明顯等問題,咱們在run方法中添加了sleep語句,這樣就 強制當前正在執行的線程休眠(暫停執行),以「減慢線程」。其實當咱們調用了sleep方法以後,當前執行的線程就進入到「休眠狀態」,其實就是所謂的Timed Waiting(計時等 待),那麼咱們經過一個案例加深對該狀態的一個理解。設計
1 package demosummary.threadstate; 2
3 /**
4 * 實現一個計數器,計數到100,在每一個數字之間暫停1秒,每隔10個數字輸出一個字符串 5 */
6 public class ThreadState extends Thread { 7 @Override 8 public void run() { 9 for (int i = 1; i < 100; i++) { 10 if (i % 10 == 0) { 11 System.out.println("每隔10個數字輸出一個字符串"); 12 } 13 System.out.println(i); 14 try { 15 Thread.sleep(1000); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 } 21
22 public static void main(String[] args) { 23 new ThreadState().start(); 24 } 25 }
經過案例能夠發現,sleep方法的使用仍是很簡單的。咱們須要記住下面幾點:
1. 進入 TIMED_WAITING 狀態的一種常見情形是調用的 sleep 方法,單獨的線程也能夠調用,不必定非要有協 做關係。 code
2. 爲了讓其餘線程有機會執行,能夠將Thread.sleep()的調用放線程run()以內。這樣才能保證該線程執行過程 中會睡眠 對象
3. sleep與鎖無關,線程睡眠到期自動甦醒,並返回到Runnable(可運行)狀態。blog
tip:sleep()中指定的時間是線程不會運行的最短期。所以,sleep()方法不能保證該線程睡眠到期後就開始馬上執行生命週期
Timed Waiting線程狀態圖ip
BLOCKED(鎖阻塞)
Blocked狀態在API中的介紹爲:一個正在阻塞等待一個監視器鎖(鎖對象)的線程處於這一狀態,好比,線程A與線程B代碼中使用同一鎖,若是線程A獲 取到鎖,線程A進入到Runnable狀態,那麼線程B就進入到Blocked鎖阻塞狀態。
blocked線程狀態圖
Waiting(無限等待)
Wating狀態在API中介紹爲:一個正在無限期等待另外一個線程執行一個特別的(喚醒)動做的線程處於這一狀態
1 package demosummary.threadstate; 2
3 public class ThreadWaiting { 4 public static Object obj = new Object(); 5
6 public static void main(String[] args) { 7 new Thread(new Runnable() { 8 @Override 9 public void run() { 10 while (true) { 11 synchronized (obj) { 12 try { 13 System.out.println(Thread.currentThread().getName()+"獲取到鎖對象,調用wait方法,進入等待狀態"); 14 obj.wait(); 15 //也能夠設置等待時間,時間到自動喚醒 16 //obj.wait(3000);
17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 System.out.println(Thread.currentThread().getName()+"---從waiting狀態醒來,繼續執行"); 21 } 22 } 23 } 24 },"等待線程").start(); 25 new Thread(new Runnable() { 26 @Override 27 public void run() { 28 while (true) { 29 try { 30 System.out.println(Thread.currentThread().getName()+"---等待三秒後自動喚醒"); 31 Thread.sleep(3000); 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35
36 synchronized (obj) { 37 System.out.println(Thread.currentThread().getName() + "獲取到鎖對象,調用notify方法,釋放對象"); 38 obj.notify(); 39 } 40 } 41 } 42 },"等待線程").start(); 43 } 44 }
經過上述案例咱們會發現,一個調用了某個對象的 Object.wait 方法的線程會等待另外一個線程調用此對象的 Object.notify()方法 或 Object.notifyAll()方法。其實waiting狀態並非一個線程的操做,它體現的是多個線程間的通訊,能夠理解爲多個線程之間的協做關係, 多個線程會爭取鎖,同時相互之間又存在協做關係。就比如在公司裏你和你的同事們,大家可能存在晉升時的競 爭,但更多時候大家更可能是一塊兒合做以完成某些任務。
當多個線程協做時,好比A,B線程,若是A線程在Runnable(可運行)狀態中調用了wait()方法那麼A線程就進入 了Waiting(無限等待)狀態,同時失去了同步鎖。假如這個時候B線程獲取到了同步鎖,在運行狀態中調用了 notify()方法,那麼就會將無限等待的A線程喚醒。注意是喚醒,若是獲取到鎖對象,那麼A線程喚醒後就進入 Runnable(可運行)狀態;若是沒有獲取鎖對象,那麼就進入到Blocked(鎖阻塞狀態)
咱們在翻閱API的時候會發現Timed Waiting(計時等待) 與 Waiting(無限等待) 狀態聯繫仍是很緊密的, 好比Waiting(無限等待) 狀態中wait方法是空參的,而timed waiting(計時等待) 中wait方法是帶參的。 這種帶參的方法,實際上是一種倒計時操做,至關於咱們生活中的小鬧鐘,咱們設定好時間,到時通知,但是 若是提早獲得(喚醒)通知,那麼設定好時間在通知也就顯得畫蛇添足了,那麼這種設計方案實際上是一舉兩 得。若是沒有獲得(喚醒)通知,那麼線程就處於Timed Waiting狀態,直到倒計時完畢自動醒來;若是在倒 計時期間獲得(喚醒)通知,那麼線程從Timed Waiting狀態馬上喚醒。