該如何正確的中斷一個線程的執行?
摘要:本文以一個案例的形式,來為大家詳細介紹下為何中斷執行的線程不起作用。
本文分享自華為雲社區《【高併發】我們該如何正確的中斷一個線程的執行??》,作者: 冰 河 。
寫在前面
當我們在調用Java對象的wait()方法或者線程的sleep()方法時,需要捕獲並處理InterruptedException異常。如果我們對InterruptedException異常處理不當,則會發生我們意想不到的後果!今天,我們就以一個案例的形式,來為大家詳細介紹下為何中斷執行的線程不起作用。
程序案例
例如,下面的程序代碼,InterruptedTask類實現了Runnable接口,在run()方法中,獲取當前線程的句柄,並在while(true)循環中,通過isInterrupted()方法來檢測當前線程是否被中斷,如果當前線程被中斷就退出while(true)循環,同時,在while(true)循環中,還有一行Thread.sleep(100)代碼,並捕獲了InterruptedException異常。整個代碼如下所示。
package io.binghe.concurrent.lab08;
/**
* @author binghe
* @version 1.0.0
* @description 線程測試中斷
*/
public class InterruptedTask implements Runnable{
@Override
public void run() {
Thread currentThread = Thread.currentThread();
while (true){
if(currentThread.isInterrupted()){
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
上述代碼的本意是通過isInterrupted()方法檢查線程是否被中斷了,如果中斷了就退出while循環。其他線程通過調用執行線程的interrupt()方法來中斷執行線程,此時會設置執行線程的中斷標誌位,從而使currentThread.isInterrupted()返回true,這樣就能夠退出while循環。
這看上去沒啥問題啊!但真的是這樣嗎?我們創建一個InterruptedTest類用於測試,代碼如下所示。
package io.binghe.concurrent.lab08;
/**
* @author binghe
* @version 1.0.0
* @description 測試線程中斷
*/
public class InterruptedTest {
public static void main(String[] args){
InterruptedTask interruptedTask = new InterruptedTask();
Thread interruptedThread = new Thread(interruptedTask);
interruptedThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
interruptedThread.interrupt();
}
}
我們運行main方法,如下所示。

這竟然跟我們想象的不一樣!不一樣!不一樣!這是為什麼呢?
問題分析
上述代碼明明調用了線程的interrupt()方法來中斷線程,但是卻並沒有起到啥作用。原因是線程的run()方法在執行的時候,大部分時間都是阻塞在sleep(100)上,當其他線程通過調用執行線程的interrupt()方法來中斷執行線程時,大概率的會觸發InterruptedException異常,在觸發InterruptedException異常的同時,JVM會同時把線程的中斷標誌位清除,所以,這個時候在run()方法中判斷的currentThread.isInterrupted()會返回false,也就不會退出當前while循環了。
既然問題分析清除了,那如何中斷線程並退出程序呢?
問題解決
正確的處理方式應該是在InterruptedTask類中的run()方法中的while(true)循環中捕獲異常之後重新設置中斷標誌位,所以,正確的InterruptedTask類的代碼如下所示。
package io.binghe.concurrent.lab08;
/**
* @author binghe
* @version 1.0.0
* @description 中斷線程測試
*/
public class InterruptedTask implements Runnable{
@Override
public void run() {
Thread currentThread = Thread.currentThread();
while (true){
if(currentThread.isInterrupted()){
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
currentThread.interrupt();
}
}
}
}
可以看到,我們在捕獲InterruptedException異常的catch代碼塊中新增了一行代碼。
currentThread.interrupt();
這就使得我們捕獲到InterruptedException異常後,能夠重新設置線程的中斷標誌位,從而中斷當前執行的線程。
我們再次運行InterruptedTest類的main方法,如下所示。

總結
處理InterruptedException異常時要小心,如果在調用執行線程的interrupt()方法中斷執行線程時,拋出了InterruptedException異常,則在觸發InterruptedException異常的同時,JVM會同時把執行線程的中斷標誌位清除,此時調用執行線程的isInterrupted()方法時,會返回false。此時,正確的處理方式是在執行線程的run()方法中捕獲到InterruptedException異常,並重新設置中斷標誌位(也就是在捕獲InterruptedException異常的catch代碼塊中,重新調用當前線程的interrupt()方法)。
- 使用卷積神經網絡實現圖片去摩爾紋
- 內核不中斷前提下,Gaussdb(DWS)內存報錯排查方法
- 簡述幾種常用的排序算法
- 自動調優工具AOE,讓你的模型在昇騰平台上高效運行
- GaussDB(DWS)運維:導致SQL執行不下推的改寫方案
- 詳解目標檢測模型的評價指標及代碼實現
- CosineWarmup理論與代碼實戰
- 淺談DWS函數出參方式
- 代碼實戰帶你瞭解深度學習中的混合精度訓練
- python進階:帶你學習實時目標跟蹤
- Ascend CL兩種數據預處理的方式:AIPP和DVPP
- 詳解ResNet 網絡,如何讓網絡變得更“深”了
- 帶你掌握如何查看並讀懂昇騰平台的應用日誌
- InstructPix2Pix: 動動嘴皮子,超越PS
- 何為神經網絡卷積層?
- 在昇騰平台上對TensorFlow網絡進行性能調優
- 介紹3種ssh遠程連接的方式
- 分佈式數據庫架構路線大揭祕
- DBA必備的Mysql知識點:數據類型和運算符
- 5個高併發導致數倉資源類報錯分析