1. 程式人生 > >Java執行緒Thread之interrupt中斷解析

Java執行緒Thread之interrupt中斷解析

轉載請標明出處:
http://blog.csdn.net/hesong1120/article/details/79164445
本文出自:hesong的專欄

這一篇我們說說Java執行緒Thread的interrupt中斷機制。

interrupt之中斷狀態標記

interrupt中斷機制中有如下方法:
- Thread.interrupt(),設定當前中斷標記為true(類似屬性的set方法)
- Thread.isInterrupted(),檢測當前的中斷標記(類似屬性的get方法)
- Thread.interrupted(),檢測當前的中斷標記,然後重置中斷標記為false(類似屬性的get方法+set方法)
因此interrupt中斷機制並不是真正的將當前執行緒中斷,而是一箇中斷標記的變化。我們先用例子來測試一下。

public class InterruptTest {
   //這裡用來列印消耗的時間
  private static long time = 0;
  private static void resetTime(){
    time = System.currentTimeMillis();
  }
  private static void printContent(String content){
    System.out.println(content + "     時間:" + (System.currentTimeMillis() - time));
  }

  public
static void main(String[] args) { test1(); } private static void test1(){ Thread1 thread1 = new Thread1(); thread1.start(); //延時3秒後interrupt中斷 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } thread1.interrupt(); printContent("執行中斷"
); } private static class Thread1 extends Thread{ @Override public void run() { resetTime(); int num = 0; while (true){ if(isInterrupted()){ printContent("當前執行緒 isInterrupted"); break; } num++; if(num % 100 == 0){ printContent("num : " + num); } } } } }

以上程式碼是開啟一個Thread1執行緒,在Thread1執行緒的while迴圈中不斷對num加1,每到100的倍數列印一次(防止列印太快)。然後主執行緒在sleep了3000毫秒後,呼叫Thread1執行緒的interrupt方法。那麼我們看看輸出結果:

intterupt中斷

可以看到,在耗時3000毫秒左右,也就是主執行緒sleep之後執行thread1.interrupt();後,Thread1執行緒停止了,而Thread1執行緒的停止是因為while迴圈中的isInterrupted方法返回了true,所以break退出了while迴圈,也就是說interrupt和isInterrupted在這裡起到的作用就相當於setXX和getXX的作用,維護著一個boolean變數。

interrupt之中斷異常處理

當然interrupt機制並不僅僅是一箇中斷狀態位的變化和檢測,它還可以進行中斷異常的處理。我們知道Thread.sleep()方法需要捕獲中斷異常,那接下來我們往其中新增一個sleep延時試試

  while (true){
    if(isInterrupted()){
      printContent("當前執行緒 isInterrupted");
      break;
    }

    num++;

    //sleep一下
    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    if(num % 100 == 0){
      printContent("num : " + num);
    }
  }

我們再看看輸出結果:

intterupt中斷

這裡我們會發現,sleep睡眠之後,輸出的num值明顯小了好多(沒睡眠時num都達到10億的大小了,看來CPU執行簡單運算還是非常快的),哈哈,不過這不是重點,重點是是看到輸出了一個異常,還有就是輸出異常後,isInterrupted輸出返回false,Thread1執行緒又繼續執行下去了,並沒有退出while迴圈。那麼這是為什麼呢?我們只是加了一個sleep睡眠而已。

如果Thread1執行緒中有執行需要捕獲InterruptedException異常的操作,比如Thread的sleep,join方法,Object的wait,Condition的await等,它是強制需要捕獲InterruptedException異常的,那麼當thread1.interrupt方法呼叫之後,它會給thread1執行緒丟擲一個InterruptedException異常,那麼在while迴圈中,就能捕獲到這個異常然後這個異常丟擲之後,又會馬上將執行緒中斷標識重置為false,因此在下次的while迴圈中判斷isInterrupted時,它是false,也就不會break,然後while迴圈會一直執行下去。

因此interrupt()方法會根據thread執行緒中的run方法裡是否有必須捕獲InterruptedException異常的程式碼,而做出不同操作:
- 如果沒有必須捕獲InterruptedException異常的程式碼(比如Thread.sleep()),則isInterrupted()會返回true,此時可以在isInterrupted的判斷中處理中斷變化。
- 如果有必須捕獲InterruptedException異常的程式碼(比如Thread.sleep()),則會丟擲InterruptedException異常,並進行捕獲,同時重置isInterrupted為false,此時得在異常捕獲中處理中斷變化。

interrupt的應用場景

通常interrupt適用於線上程執行中的迴圈標記判斷,例如

while(!isInterrupted()){
    ...
}

但是如果在本次迴圈中出現阻塞了,那麼執行緒就無法判斷下次的isInterrupted標記,那麼即便呼叫了interrupt()方法也無法退出迴圈,也就無法退出執行緒。例如
}

while(!isInterrupted()){
    ...

    while(true){
        //執行緒卡在這裡了,則無法響應interrupte機制了
    }
}

這樣的話,interrupt就沒轍了,執行緒會一直執行下去,不會被中斷停止。

測試例子檢視 我的GitHub–JavaTest

我的部落格
GitHub
我的簡書
群號:194118438,歡迎入群
微信公眾號 hesong ,微信掃一掃下方二維碼即可關注: