java 線程的幾種狀態

java thread的運行週期中, 有幾種狀態, 在 java.lang.Thread.State 中有詳細定義和說明: java

NEW 狀態是指線程剛建立, 還沒有啓動 併發

RUNNABLE 狀態是線程正在正常運行中, 固然可能會有某種耗時計算/IO等待的操做/CPU時間片切換等, 這個狀態下發生的等待通常是其餘系統資源, 而不是鎖, Sleep等 異步

BLOCKED  這個狀態下, 是在多個線程有同步操做的場景, 好比正在等待另外一個線程的synchronized 塊的執行釋放, 或者可重入的 synchronized塊裏別人調用wait() 方法, 也就是這裏是線程在等待進入臨界區

WAITING  這個狀態下是指線程擁有了某個鎖以後, 調用了他的wait方法, 等待其餘線程/鎖擁有者調用 notify / notifyAll 一遍該線程能夠繼續下一步操做, 這裏要區分 BLOCKED 和 WATING 的區別, 一個是在臨界點外面等待進入, 一個是在理解點裏面wait等待別人notify, 線程調用了join方法 join了另外的線程的時候, 也會進入WAITING狀態, 等待被他join的線程執行結束 jvm

TIMED_WAITING  這個狀態就是有限的(時間限制)的WAITING, 通常出如今調用wait(long), join(long)等狀況下, 另一個線程sleep後, 也會進入TIMED_WAITING狀態 ide

TERMINATED 這個狀態下表示 該線程的run方法已經執行完畢了, 基本上就等於死亡了(當時若是線程被持久持有, 可能不會被回收) 工具

下面談談如何讓線程進入以上幾種狀態:

1. NEW, 這個最簡單了,  
 
     static void NEW() {
          Thread t = new Thread ();
         System. out.println(t.getState());
    }
 
輸出NEW
 
2. RUNNABLE, 也簡單, 讓一個thread start, 同時代碼裏面不要sleep或者wait等
 
   private static void RUNNABLE() {
         Thread t = new Thread(){
             
              public void run(){
                  for(int i=0; i<Integer.MAX_VALUE; i++){
                      System. out.println(i);
                 }
             }
             
         };
         
         t.start();
    }
 
 71e94764e28c7f8bbd3ef91c1c0088b4
 
3. BLOCKED, 這個就必須至少兩個線程以上, 而後互相等待synchronized 塊
          
     private static void BLOCKED() {
         
          final Object lock = new Object();
         
         Runnable run = new Runnable() {
             
              @Override
              public void run() {
                  for(int i=0; i<Integer.MAX_VALUE; i++){
                      
                       synchronized (lock) {
                          System. out.println(i);
                      }
                      
                 }
             }
         };
         
         Thread t1 = new Thread(run);
         t1.setName( 「t1」);
         Thread t2 = new Thread(run);
         t2.setName( 「t2」);
         
         t1.start();
         t2.start();
         
    }
 
8e9ad1eadf9d38c0b6c8cb024cb36c0c
這時候, 一個在RUNNABLE, 另外一個就會在BLOCKED (等待另外一個線程的 System.out.println.. 這是個IO操做, 屬於系統資源, 不會形成WAITING等)
 
4. WAITING, 這個須要用到生產者消費者模型, 當生產者生產過慢的時候, 消費者就會等待生產者的下一次notify
 
     private static void WAITING() {
 
          final Object lock = new Object();
         Thread t1 = new Thread(){
              @Override
              public void run() {
                 
                  int i = 0;
                 
                  while(true ){
                       synchronized (lock) {
                           try {
                               lock.wait();
                          } catch (InterruptedException e) {
                          }
                          System. out.println(i++);
                      }
                 }
             }
         };
         
         Thread t2 = new Thread(){
              @Override
              public void run() {
                 
                  while(true ){
                       synchronized (lock) {
                           for(int i = 0; i< 10000000; i++){
                              System. out.println(i);
                          }
                          lock.notifyAll();
                      }
                      
                 }
             }
         };
         
         t1.setName( 「^^t1^^」);
         t2.setName( 「^^t2^^」);
         
         t1.start();
         t2.start();
    }
 
 b43a3d9b67bab266ffea4537fb043bba
 
5. TIMED_WAITING, 這個僅須要在4的基礎上, 在wait方法加上一個時間參數進行限制就OK了.
 
把4中的synchronized 塊改爲以下就能夠了.
 
synchronized  (lock) {
   try {
      lock.wait(60 * 1000L);
   }  catch  (InterruptedException e) {
   }
   System. out .println(i++);
 }
 
 88d9047d8a709c2d63c695bcf58a0297
另外看stack的輸出,  他叫 TIMED_WAITING(on  object monitor) , 說明括號後面還有其餘的狀況, 好比sleep, 咱們直接把t2的for循環改爲sleep試試:
 
synchronized (lock) {
    
    try {
          sleep(30*1000L);
    } catch (InterruptedException e) {
    }
    lock.notifyAll();
}
a37ef4c72c00e793f8b6c746d74fd4d9 
 
看到了吧, t2的state是 TIMED_WAITING( sleeping),  而t1依然是on object monitor , 由於t1仍是wait在等待t2 notify, 而t2是本身sleep
 
另外, join操做也是進入 on object monitor
 
6. TERMINATED, 這個狀態只要線程結束了run方法, 就會進入了…
 
    private static void TERMINATED() {
         Thread t1 = new Thread();
         t1.start();
         System. out.println(t1.getState());
          try {
             Thread. sleep(1000L);
         } catch (InterruptedException e) {
         }
         System. out.println(t1.getState());
    }
輸出: 
RUNNABLE
TERMINATED
 
因爲線程的start方法是異步啓動的, 因此在其執行後當即獲取狀態有可能纔剛進入RUN方法且還未執行完畢
 
 
廢話了這麼多, 瞭解線程的狀態究竟有什麼用?
因此說這是個釣魚貼麼…
 
好吧, 一句話, 在找到系統中的潛在性能瓶頸有做用.
 
當java系統運行慢的時候, 咱們想到的應該先找到性能的瓶頸, 而jstack等工具, 經過jvm當前的stack能夠看到當前整個vm全部線程的狀態, 當咱們看到一個線程狀態常常處於
WAITING 或者 BLOCKED的時候, 要當心了, 他可能在等待資源常常沒有獲得釋放(固然, 線程池的調度用的也是各類隊列各類鎖, 要區分一下, 好比下圖)
6db341bbd7680bbc2e6ae37a66329397
這是個經典的併發包裏面的線程池, 其調度隊列用的是LinkedBlockingQueue, 執行take的時候會block住, 等待下一個任務進入隊列中, 而後進入執行, 這種理論上不是系統的性能瓶頸, 找瓶頸通常先找本身的代碼stack,再去排查那些開源的組件/JDK的問題
 
排查問題的幾個思路:
 
0. 如何跟蹤一個線程?
看到上面的stack輸出沒有, 第一行是內容是 threadName priority tid nid desc
更過跟蹤tid, nid 均可以惟一找到該線程.
 
1. 發現有線程進入BLOCK, 並且持續很久, 這說明性能瓶頸存在於synchronized塊中, 由於他一直block住, 進不去, 說明另外一個線程一直沒有處理好, 也就這個synchronized塊中處理速度比較慢, 而後再深刻查看. 固然也有可能同時block的線程太多, 排隊過久形成.
 
2. 發現有線程進入WAITING, 並且持續很久, 說明性能瓶頸存在於觸發notify的那段邏輯. 固然還有就是同時WAITING的線程過多, 總是等不到釋放.
 
3. 線程進入TIME_WAITING 狀態且持續很久的, 跟2的排查方式同樣.
 
 
上面的黑底白字截圖都是經過jstack打印出來的, 能夠直接定位到你想知道的線程的執行棧, 這對java性能瓶頸的分析是有極大做用的.
 
NOTE: 上面全部代碼都是爲了跟蹤線程的狀態而寫的, 千萬不要在線上應用中這麼寫…
相關文章
相關標籤/搜索