Java多線程之interrupt()的深度研究

原文地址:http://www.cnblogs.com/carmanloneliness/p/3516405.htmlhtml


近期學習Java多線程的中斷機制,網上的帖子說得很淺,並沒深究其原理。看了Java源碼,對Java的中斷機制有了略深刻的理解,在這篇文章中向感興趣的網友分享下。這篇文章主要經過一個典型例子對中斷機制進行剖析。java

  一:一些概念和重要方法多線程

  interrupt status(中斷狀態):請記住這個術語,中斷機制就是圍繞着這個字段來工做的。在Java源碼中表明中斷狀態的字段是:private volatile Interruptible blocker;對「Interruptible」這個類不須要深刻分析,對於「blocker」變量有如下幾個操做。ide

  1.默認blocker=null; ®1學習

  2.調用方法「interrupt0();」將會致使「該線程的中斷狀態將被設置(JDK文檔中術語)」。®2測試

  3.再次調用「interrupt0();」將會致使「其中斷狀態將被清除(同JDK文檔中術語)」®3this

  注:這三點很重要,接下來文章中會用來®1®2®3代替。spa

明白了第一點來看下文檔中對於中斷線程相關方法的描述。線程

  1.public void interrupt();code

    中斷線程。若是線程在調用 Object 類的 wait()wait(long) 或 wait(long, int) 方法,或者該類的 join()join(long)join(long, int)sleep(long) 或 sleep(long, int) 方法

  過程當中受阻,則其中斷狀態將被清除,它還將收到一個 InterruptedException。 

  2.public static boolean interrupted();

    測試當前線程是否已經中斷。線程的中斷狀態 由該方法清除。線程中斷被忽略,由於在中斷時不處於活動狀態的線程將由此返回 false 的方法反映出來。

  •       返回:

  •     若是當前線程已經中斷,則返回 true;不然返回 false

  •       另請參見:

  • isInterrupted()

  3.public boolean isInterrupted();

    測試線程是否已經中斷。線程的中斷狀態 不受該方法的影響。線程中斷被忽略,由於在中斷時不處於活動狀態的線程將由此返回 false 的方法反映出來。

  返回:若是該線程已經中斷,則返回 true;不然返回 false

  另請參見:interrupted()

  <!--來自JDK API文檔-->

    以上三段中關於線程的中斷狀態 由該方法清除的描述,在源碼層面就是®3調用。

  •  接下來講一下"interrupted()"和"isInterrupted()"兩個方法的相同點和不一樣點。在這以前看一下源碼中兩個方法的代碼,以下:

    複製代碼

     1 public static boolean interrupted() { 2     return currentThread().isInterrupted(true); 3     } 4 public boolean isInterrupted() { 5     return isInterrupted(false); 6     } 7  /** 8      * Tests if some Thread has been interrupted.  The interrupted state 9      * is reset or not based on the value of ClearInterrupted that is10      * passed.11      */12 private native boolean isInterrupted(boolean ClearInterrupted);

    複製代碼

      相同點都是判斷線程的interrupt status是否被設置,若被設置返回true,不然返回false.區別有兩點:一:前者是static方法,調用者是current thread,然後者是普通方法,調用者是this current.二:它們其實都調用了Java中的一個native方法isInterrupted(boolean ClearInterrupted); 不一樣的是前者傳入了參數true,後者傳入了false.意義就是:前者將清除線程的interrupt state(®3),調用後者線程的interrupt state不受影響。

    二:例子。

      接下來看一個例子,這個例子說明了兩個問題。1.調用interrupt()方法並不會中斷一個正在運行的線程.2.若調用sleep()而使線程處於阻塞狀態,這時調用interrupt()方法,會拋出InterruptedException,從而使線程提早結束阻塞狀態,退出阻塞代碼。以下:

    複製代碼

     1 package interrupt; 2  3 public class Main { 4     /** 5      * @param args 6      */ 7     public static void main(String[] args) { 8         Main main = new Main(); 9         Thread t = new Thread(main.runnable);10         System.out.println("mainmainmain");11         t.start();12         try {13             Thread.sleep(2000);14         } catch (InterruptedException e) {15             // TODO Auto-generated catch block16             e.printStackTrace();17         }18         t.interrupt();19     }20 21     Runnable runnable = new Runnable() {22         @Override23         public void run() {24             int i = 0;25             try {26                 while (i < 1000) {27                     Thread.sleep(500);28                     System.out.println(i++);29                 }30             } catch (InterruptedException e) {31                 e.printStackTrace();32             }33         }34     };35 }

    複製代碼

    運行結果:

    複製代碼

    1 mainmainmain2 03 14 25 java.lang.InterruptedException: sleep interrupted6     at java.lang.Thread.sleep(Native Method)7     at interrupt.Main$1.run(Main.java:27)8     at java.lang.Thread.run(Thread.java:619)

    複製代碼

    三:分析下例子中的中斷機制

     1.爲何調用interrupt()並不能中斷線程?

    複製代碼

     1 public void interrupt() { 2     if (this != Thread.currentThread()) 3         checkAccess(); 4  5     synchronized (blockerLock) { 6         Interruptible b = blocker; 7         if (b != null) { 8         interrupt0();        // Just to set the interrupt flag 9         b.interrupt();10         return;11         }12     }13     interrupt0();14     }

    複製代碼

    如上是Java源碼中的代碼,由此咱們看出問題的答案。線程的blocker字段(也就是interrupt status)默認是null(®1)。調用interrupt()方法時,只是運行了®2,並無進入if語句,因此沒調用真正執行中斷的代碼b.interrupt().

    2.若調用sleep()而使線程處於阻塞狀態,這時調用interrupt()方法,會拋出InterruptedException,從而使線程提早結束阻塞狀態,退出阻塞代碼。爲何?

    由上圖可看出例子中30行代碼鋪好的異常實際上是interrupt()拋出的,而不是sleep()拋出的。

相關文章
相關標籤/搜索