java高并發(fā)InterruptedException異常引發(fā)思考
前言
InterruptedException異??赡軟]你想的那么簡單!
當我們在調用Java對象的wait()方法或者線程的sleep()方法時,需要捕獲并處理InterruptedException異常。如果我們對InterruptedException異常處理不當,則會發(fā)生我們意想不到的后果!
程序案例
例如,下面的程序代碼,InterruptedTask類實現(xiàn)了Runnable接口,在run()方法中,獲取當前線程的句柄,并在while(true)循環(huán)中,通過isInterrupted()方法來檢測當前線程是否被中斷,如果當前線程被中斷就退出while(true)循環(huán),同時,在while(true)循環(huán)中,還有一行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循環(huán)。其他線程通過調用執(zhí)行線程的interrupt()方法來中斷執(zhí)行線程,此時會設置執(zhí)行線程的中斷標志位,從而使currentThread.isInterrupted()返回true,這樣就能夠退出while循環(huán)。
這看上去沒啥問題??!但真的是這樣嗎?我們創(chuàng)建一個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()方法在執(zhí)行的時候,大部分時間都是阻塞在sleep(100)上,當其他線程通過調用執(zhí)行線程的interrupt()方法來中斷執(zhí)行線程時,大概率的會觸發(fā)InterruptedException異常,在觸發(fā)InterruptedException異常的同時,JVM會同時把線程的中斷標志位清除,所以,這個時候在run()方法中判斷的currentThread.isInterrupted()會返回false,也就不會退出當前while循環(huán)了。
既然問題分析清除了,那如何中斷線程并退出程序呢?
問題解決
正確的處理方式應該是在InterruptedTask類中的run()方法中的while(true)循環(huán)中捕獲異常之后重新設置中斷標志位,所以,正確的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異常后,能夠重新設置線程的中斷標志位,從而中斷當前執(zhí)行的線程。
我們再次運行InterruptedTest類的main方法,如下所示。

總結
處理InterruptedException異常時要小心,如果在調用執(zhí)行線程的interrupt()方法中斷執(zhí)行線程時,拋出了InterruptedException異常,則在觸發(fā)InterruptedException異常的同時,JVM會同時把執(zhí)行線程的中斷標志位清除,此時調用執(zhí)行線程的isInterrupted()方法時,會返回false。
此時,正確的處理方式是在執(zhí)行線程的run()方法中捕獲到InterruptedException異常,并重新設置中斷標志位(也就是在捕獲InterruptedException異常的catch代碼塊中,重新調用當前線程的interrupt()方法)。
寫在最后
最后,附上并發(fā)編程需要掌握的核心技能知識圖,祝大家在學習并發(fā)編程時,少走彎路。

以上就是java高并發(fā)InterruptedException異常引發(fā)思考的詳細內容,更多關于java高并發(fā)InterruptedException異常的資料請關注腳本之家其它相關文章!
相關文章
教你怎么用SpringBoot+Mybati-Plus快速搭建代碼
Mybatis自身通過了逆向工程來幫助我們快速生成代碼,但Mybatis-plus卻更加強大,不僅僅可以生成dao,pojo,mapper,還有基本的controller和service層代碼,接下來我們來寫一個簡單的人門案例是看看如何mybatis-plus是怎么實現(xiàn)的,需要的朋友可以參考下2021-06-06
java顯示當前運行時的參數(shù)(java運行參數(shù))
這篇文章主要介紹了java顯示當前運行時參數(shù)的示例(java運行參數(shù)),需要的朋友可以參考下2014-04-04
Spring Boot 如何使用Liquibase 進行數(shù)據(jù)庫遷移(操作方法)
在Spring Boot應用程序中使用Liquibase進行數(shù)據(jù)庫遷移是一種強大的方式來管理數(shù)據(jù)庫模式的變化,本文重點講解如何在Spring Boot應用程序中使用Liquibase進行數(shù)據(jù)庫遷移,從而更好地管理數(shù)據(jù)庫模式的變化,感興趣的朋友跟隨小編一起看看吧2023-09-09
Java利用文件輸入輸出流實現(xiàn)文件夾內所有文件拷貝到另一個文件夾
這篇文章主要介紹了Java實現(xiàn)文件夾內所有文件拷貝到另一個文件夾,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-03-03
Springboot在有鎖的情況下正確使用事務的實現(xiàn)代碼
這篇文章主要介紹了Springboot在有鎖的情況下如何正確使用事務,今天通過一個實驗給大家分析一下商品超賣問題,模擬場景分析通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2021-12-12

