首頁  >  文章  >  Java  >  java高並發InterruptedException異常問題怎麼解決

java高並發InterruptedException異常問題怎麼解決

WBOY
WBOY轉載
2023-04-30 08:46:061647瀏覽

前言

InterruptedException異常可能沒你想的那麼簡單!

當我們在呼叫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方法,如下所示。

java高並發InterruptedException異常問題怎麼解決

問題分析

上述程式碼明明呼叫了線程的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方法,如下所示。

java高並發InterruptedException異常問題怎麼解決

總結

處理InterruptedException異常時要小心,如果在呼叫執行緒的interrupt()方法中斷執行緒時,拋出了InterruptedException異常,則在觸發InterruptedException異常的同時,JVM會同時把執行緒的中斷標誌位元清除,此時呼叫執行執行緒的isInterrupted()方法時,就會回傳false。

此時,正確的處理方式是在執行線程的run()方法中捕獲到InterruptedException異常,並重新設定中斷標誌位元(也就是在捕獲InterruptedException異常的catch程式碼區塊中,重新呼叫目前執行緒的interrupt()方法)。

以上是java高並發InterruptedException異常問題怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除