聊起中斷,你們可能最熟悉的例子就是線程休眠。下面就是一個線程休眠的 demo,在這個例子中,當咱們調用 sleep
方法,該方法將會拋出一個須要捕獲的中斷異常,這裏捕獲該異常並直接返回。html
for (int i = 0; i < somethings.size(); i++) { // 休眠 4 s try { Thread.sleep(4000); } catch (InterruptedException e) { // 拋出中斷異常 return; } // 輸出 System.out.println(somethings.get(i)); }
除了 InterruptedException
中斷異常,另外還有三個中斷相關的方法,三個方法都與線程相關。java
interrupt
方法用於中斷線程,可是並非說該方法就能直接使線程中止。面試
下面使用 interrupt
中斷線程,這裏咱們指望中斷直接中止子線程輸出。可是當主線程調用子線程 interrupt
方法,子線程並卻沒有被終止,還在繼續打印數字。ide
Runnable interruptedTask=new Runnable() { @Override public void run() { for (int i = 0; i <Integer.MAX_VALUE ; i++) { System.out.println(i); } } }; Thread interruptThread=new Thread(interruptedTask); interruptThread.start(); // 休眠 5 s, TimeUnit.SECONDS.sleep(2); // 中斷當前線程 interruptThread.interrupt(); // 再次休眠,觀察子線程 TimeUnit.SECONDS.sleep(2);
引用 Java 官方對於中斷的解釋:idea
An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate
中斷僅僅只是代表這個線程能夠中止,可是線程是否中止徹底取決於線程本身。只有線程相互協做,才能更好的中止線程。spa
每一個線程都包含一個內部標誌,用來表示中斷狀態。調用線程的 interrupt
方法將會設置該狀態位,對於 Thread#sleep
等阻塞方法,將會拋出 InterruptedException
,並清除中斷標誌。線程
咱們可使用 thread#isInterrupted
或 Thread#interrupted
檢查中斷狀態。可是須要注意,兩個方法存在一些區別,Thread#interrupted
爲靜態類方法,該方法檢測到中斷以後就會清除中斷標誌。日誌
上面的方法咱們只要加上中斷狀態判斷就也能夠中止線程。code
Runnable interruptedTask=new Runnable() { @Override public void run() { for (int i = 0; i <Integer.MAX_VALUE ; i++) { // 一旦檢測到中斷標誌,中止線程 if(Thread.interrupted()){ System.out.println("interrupted!!!!"); break; } System.out.println(i); } } }; Thread interruptThread=new Thread(interruptedTask); interruptThread.start(); // 休眠 5 s, TimeUnit.SECONDS.sleep(2); // 中斷當前線程 interruptThread.interrupt(); // 再次休眠,觀察子線程 TimeUnit.SECONDS.sleep(2); }
因爲中斷異常是一個 checked exception,咱們不得不須要處理該異常。若是咱們能夠保證該異常不影響應用,咱們能夠直接『吃掉』這個異常。其餘狀況下咱們須要正確處理這個異常。htm
最簡單的作法就是不處理該異常,直接向上拋出中斷異常,讓上層調用者決定如何處理。
可是有些狀況下,卻不適合上面的作法,這種狀況下咱們須要在 catch 中處理中斷。若是實在不知道如何處理,那就是記錄該異常,並使用日誌方式輸出。
上面咱們說到,對於一些阻塞方法如 Thread#sleep
,將會拋出中斷異常。可是對於 Socket 等阻塞 IO 調用,並不會拋出這個異常。也就是說中斷並不會中止阻塞 IO 的調用。
這是由於當調用 Thread#sleep
等阻塞方法時,Java 線程狀態將會從 RUNNABLE
轉變爲 TIMED_WAITING
或 WATTING
。而當線程阻塞在 IO 讀取時,Java 線程實際狀態卻仍是 RUNNABLE
。若是你對這個線程狀態還有疑惑,能夠閱讀下這篇文章 面試官:都說阻塞 I/O 模型將會使線程休眠,爲何 Java 線程狀態倒是 RUNNABLE?,深刻理解一下線程狀態。
本文首發於studyidea.cn
歡迎關注個人公衆號:程序通事,得到平常乾貨推送。若是您對個人專題內容感興趣,也能夠關注個人博客: studyidea.cn