java高并發(fā)InterruptedException異常引發(fā)思考
前言
InterruptedException異??赡軟]你想的那么簡(jiǎn)單!
當(dāng)我們?cè)谡{(diào)用Java對(duì)象的wait()方法或者線程的sleep()方法時(shí),需要捕獲并處理InterruptedException異常。如果我們對(duì)InterruptedException異常處理不當(dāng),則會(huì)發(fā)生我們意想不到的后果!
程序案例
例如,下面的程序代碼,InterruptedTask類實(shí)現(xiàn)了Runnable接口,在run()方法中,獲取當(dāng)前線程的句柄,并在while(true)循環(huán)中,通過isInterrupted()方法來檢測(cè)當(dāng)前線程是否被中斷,如果當(dāng)前線程被中斷就退出while(true)循環(huán),同時(shí),在while(true)循環(huán)中,還有一行Thread.sleep(100)代碼,并捕獲了InterruptedException異常。
整個(gè)代碼如下所示。
package io.binghe.concurrent.lab08;
/**
* @author binghe
* @version 1.0.0
* @description 線程測(cè)試中斷
*/
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)。其他線程通過調(diào)用執(zhí)行線程的interrupt()方法來中斷執(zhí)行線程,此時(shí)會(huì)設(shè)置執(zhí)行線程的中斷標(biāo)志位,從而使currentThread.isInterrupted()返回true,這樣就能夠退出while循環(huán)。
這看上去沒啥問題啊!但真的是這樣嗎?我們創(chuàng)建一個(gè)InterruptedTest類用于測(cè)試,代碼如下所示。
package io.binghe.concurrent.lab08;
/**
* @author binghe
* @version 1.0.0
* @description 測(cè)試線程中斷
*/
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();
}
}
我們運(yùn)行main方法,如下所示。

這竟然跟我們想象的不一樣!不一樣!不一樣!這是為什么呢?
問題分析
上述代碼明明調(diào)用了線程的interrupt()方法來中斷線程,但是卻并沒有起到啥作用。原因是線程的run()方法在執(zhí)行的時(shí)候,大部分時(shí)間都是阻塞在sleep(100)上,當(dāng)其他線程通過調(diào)用執(zhí)行線程的interrupt()方法來中斷執(zhí)行線程時(shí),大概率的會(huì)觸發(fā)InterruptedException異常,在觸發(fā)InterruptedException異常的同時(shí),JVM會(huì)同時(shí)把線程的中斷標(biāo)志位清除,所以,這個(gè)時(shí)候在run()方法中判斷的currentThread.isInterrupted()會(huì)返回false,也就不會(huì)退出當(dāng)前while循環(huán)了。
既然問題分析清除了,那如何中斷線程并退出程序呢?
問題解決
正確的處理方式應(yīng)該是在InterruptedTask類中的run()方法中的while(true)循環(huán)中捕獲異常之后重新設(shè)置中斷標(biāo)志位,所以,正確的InterruptedTask類的代碼如下所示。
package io.binghe.concurrent.lab08;
/**
* @author binghe
* @version 1.0.0
* @description 中斷線程測(cè)試
*/
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();
}
}
}
}
可以看到,我們?cè)诓东@InterruptedException異常的catch代碼塊中新增了一行代碼。
currentThread.interrupt();
這就使得我們捕獲到InterruptedException異常后,能夠重新設(shè)置線程的中斷標(biāo)志位,從而中斷當(dāng)前執(zhí)行的線程。
我們?cè)俅芜\(yùn)行InterruptedTest類的main方法,如下所示。

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

以上就是java高并發(fā)InterruptedException異常引發(fā)思考的詳細(xì)內(nèi)容,更多關(guān)于java高并發(fā)InterruptedException異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java接口操作(繼承父類并實(shí)現(xiàn)多個(gè)接口)
這篇文章主要介紹了Java接口操作(繼承父類并實(shí)現(xiàn)多個(gè)接口),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10
SpringBoot項(xiàng)目使用jasypt加解密的方法
jasypt是一個(gè)通用的加解密庫,我們可以使用它在配置文件中對(duì)數(shù)據(jù)庫密碼進(jìn)行加密,以確保其安全性,接下來通過本文給大家介紹SpringBoot項(xiàng)目使用jasypt加解密的方法,感興趣的朋友一起看看吧2022-05-05
SpringBoot項(xiàng)目使用yml文件鏈接數(shù)據(jù)庫異常問題解決方案
在使用SpringBoot時(shí),利用yml進(jìn)行數(shù)據(jù)庫連接配置需小心數(shù)據(jù)類型區(qū)分,如果用戶名或密碼是數(shù)字,必須用雙引號(hào)包裹以識(shí)別為字符串,避免連接錯(cuò)誤,特殊字符密碼也應(yīng)用引號(hào)包裹2024-10-10
Java Caledar類(日歷類)如何判斷本周周數(shù)
這篇文章主要介紹了Java Caledar類(日歷類)如何判斷本周周數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
java區(qū)分絕對(duì)路徑和相對(duì)路徑的方法
這篇文章主要介紹了java區(qū)分絕對(duì)路徑和相對(duì)路徑的方法,實(shí)例分析了java針對(duì)路徑操作的相關(guān)技巧,需要的朋友可以參考下2015-04-04

