- Java并發編程之美
- 翟陸續 薛賓田
- 1493字
- 2019-07-25 11:54:00
1.7 線程中斷
Java中的線程中斷是一種線程間的協作模式,通過設置線程的中斷標志并不能直接終止該線程的執行,而是被中斷的線程根據中斷狀態自行處理。
● void interrupt()方法 :中斷線程,例如,當線程A運行時,線程B可以調用線程A的interrupt()方法來設置線程A的中斷標志為true并立即返回。設置標志僅僅是設置標志,線程A實際并沒有被中斷,它會繼續往下執行。如果線程A因為調用了wait系列函數、join方法或者sleep方法而被阻塞掛起,這時候若線程B調用線程A的interrupt()方法,線程A會在調用這些方法的地方拋出InterruptedException異常而返回。
● boolean isInterrupted()方法:檢測當前線程是否被中斷,如果是返回true,否則返回false。
public boolean isInterrupted() { //傳遞false,說明不清除中斷標志 return isInterrupted(false); }
● boolean interrupted()方法:檢測當前線程是否被中斷,如果是返回true,否則返回false。與isInterrupted不同的是,該方法如果發現當前線程被中斷,則會清除中斷標志,并且該方法是static方法,可以通過Thread類直接調用。另外從下面的代碼可以知道,在interrupted()內部是獲取當前調用線程的中斷標志而不是調用interrupted()方法的實例對象的中斷標志。
public static boolean interrupted() { //清除中斷標志 return currentThread().isInterrupted(true); }
下面看一個線程使用Interrupted優雅退出的經典例子,代碼如下。
public void run(){ try{ .... //線程退出條件 while(! Thread.currentThread().isInterrupted()&& more work to do){ // do more work; } }catch(InterruptedException e){ // thread was interrupted during sleep or wait } finally{ // cleanup, if required
} }
下面看一個根據中斷標志判斷線程是否終止的例子。
public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { //如果當前線程被中斷則退出循環 while (! Thread.currentThread().isInterrupted()) System.out.println(Thread.currentThread() + " hello"); } }); //啟動子線程 thread.start(); //主線程休眠1s,以便中斷前讓子線程輸出 Thread.sleep(1000); //中斷子線程 System.out.println("main thread interrupt thread"); thread.interrupt(); //等待子線程執行完畢 thread.join(); System.out.println("main is over"); }
輸出結果如下.

在如上代碼中,子線程thread通過檢查當前線程中斷標志來控制是否退出循環,主線程在休眠1s后調用thread的interrupt()方法設置了中斷標志,所以線程thread退出了循環。
下面再來看一種情況。當線程為了等待一些特定條件的到來時,一般會調用sleep函數、wait系列函數或者join()函數來阻塞掛起當前線程。比如一個線程調用了Thread. sleep(3000),那么調用線程會被阻塞,直到3s后才會從阻塞狀態變為激活狀態。但是有可能在3s內條件已被滿足,如果一直等到3s后再返回有點浪費時間,這時候可以調用該線程的interrupt()方法,強制sleep方法拋出InterruptedException異常而返回,線程恢復到激活狀態。下面看一個例子。
public static void main(String[] args) throws InterruptedException { Thread threadOne = new Thread(new Runnable() { public void run() { try { System.out.println("threadOne begin sleep for 2000 seconds"); Thread.sleep(2000000); System.out.println("threadOne awaking"); } catch (InterruptedException e) { System.out.println("threadOne is interrupted while sleeping"); return; } System.out.println("threadOne-leaving normally"); } }); //啟動線程 threadOne.start(); //確保子線程進入休眠狀態 Thread.sleep(1000); //打斷子線程的休眠,讓子線程從sleep函數返回 threadOne.interrupt(); //等待子線程執行完畢 threadOne.join(); System.out.println("main thread is over"); }
輸出結果如下。

在如上代碼中,threadOne線程休眠了2000s,在正常情況下該線程需要等到2000s后才會被喚醒,但是本例通過調用threadOne.interrupt()方法打斷了該線程的休眠,該線程會在調用sleep方法處拋出InterruptedException異常后返回。
下面再通過一個例子來了解interrupted()與isInterrupted()方法的不同之處。
public static void main(String[] args) throws InterruptedException { Thread threadOne = new Thread(new Runnable() { public void run() { for(; ; ){ } } }); //啟動線程 threadOne.start(); //設置中斷標志 threadOne.interrupt(); //獲取中斷標志 System.out.println("isInterrupted:" + threadOne.isInterrupted()); //獲取中斷標志并重置 System.out.println("isInterrupted:" + threadOne.interrupted()); //獲取中斷標志并重置 System.out.println("isInterrupted:" + Thread.interrupted()); //獲取中斷標志 System.out.println("isInterrupted:" + threadOne.isInterrupted()); threadOne.join();
System.out.println("main thread is over"); }
輸出結果如下。

第一行輸出true這個大家應該都可以想到,但是下面三行為何是false、false、true呢,不應該是true、false、false嗎?如果你有這個疑問,則說明你對這兩個函數的區別還是不太清楚。上面我們介紹了在interrupted()方法內部是獲取當前線程的中斷狀態,這里雖然調用了threadOne的interrupted()方法,但是獲取的是主線程的中斷標志,因為主線程是當前線程。threadOne.interrupted()和Thread.interrupted()方法的作用是一樣的,目的都是獲取當前線程的中斷標志。修改上面的例子為如下。
public static void main(String[] args) throws InterruptedException { Thread threadOne = new Thread(new Runnable() { public void run() { //中斷標志為true時會退出循環,并且清除中斷標志 while (! Thread.currentThread().interrupted()) { } System.out.println("threadOne isInterrupted:" + Thread.currentThread(). isInterrupted()); } }); // 啟動線程 threadOne.start(); // 設置中斷標志 threadOne.interrupt(); threadOne.join(); System.out.println("main thread is over");
}
輸出結果如下。

由輸出結果可知,調用interrupted()方法后中斷標志被清除了。
- 深度實踐OpenStack:基于Python的OpenStack組件開發
- Implementing Modern DevOps
- Advanced Machine Learning with Python
- CMDB分步構建指南
- Java面向對象思想與程序設計
- Python數據可視化:基于Bokeh的可視化繪圖
- 編寫整潔的Python代碼(第2版)
- Scratch真好玩:教小孩學編程
- 深度強化學習算法與實踐:基于PyTorch的實現
- Backbone.js Blueprints
- The DevOps 2.4 Toolkit
- Magento 1.8 Development Cookbook
- Android玩家必備
- 速學Python:程序設計從入門到進階
- Mastering Apache Storm