java線程中斷原理

稍有java基礎(chǔ)的同學(xué)都知道,在java中創(chuàng)建并啟動一個(gè)線程比較容易,而線程中斷的難度更高一些,并且使用的場景也相對較少。

interrupt()

中斷某一個(gè)線程需要調(diào)用該線程對象的interrupt方法。

public class Demo {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyTask());
        thread.start();
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
        }
        thread.interrupt();
    }
    static class MyTask implements Runnable {
        @Override
        public void run() {
            while (true) {
                System.out.println(Thread.currentThread() + " is running...");
            }
        }
    }
}

運(yùn)行代碼會發(fā)現(xiàn),即使在主線程中執(zhí)行目標(biāo)線程的interrupt()方法,但目標(biāo)線程并沒有停止執(zhí)行。這正是interrupt機(jī)制設(shè)計(jì)的特別之處,當(dāng)主線程發(fā)起目標(biāo)線程中斷的命令后,目標(biāo)線程并不會立即放棄線程的執(zhí)行權(quán)。

中斷標(biāo)志位

java interrupt中斷機(jī)制是當(dāng)主線程向目標(biāo)線程發(fā)起interrupt中斷命令后,目標(biāo)線程的中斷標(biāo)志位被置為true,目標(biāo)線程通過查詢中斷標(biāo)志位自行決定是否停止當(dāng)前線程的執(zhí)行。
這便解釋了上面的代碼中,目標(biāo)線程的中斷標(biāo)志位雖然置為true,但由于并沒有主動采取線程停止的操作,所以線程依然處于Running狀態(tài)。
查詢線程中斷標(biāo)志位的方法有兩種:isInterrupted()和interrupted(),下面分別介紹二者的區(qū)別。

isInterrupted()與interrupted()

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

public boolean isInterrupted() {
    return isInterrupted(false);
}

private native boolean isInterrupted(boolean ClearInterrupted);

直接看這兩個(gè)方法的源碼,interrupted()是靜態(tài)方法而isInterrupted()是實(shí)例方法,他們的實(shí)現(xiàn)都是調(diào)用同一個(gè)native方法。主要的區(qū)別是他們的形參ClearInterrupted傳的不一樣。interrupted()在返回中斷標(biāo)志位后會清除標(biāo)志位,isInterrupted()則不清除中斷標(biāo)志位。
接下來改造前面的代碼,實(shí)現(xiàn)線程中斷效果:

public class Demo {

    public static void main(String[] args) {
        Thread thread = new Thread(new MyTask());
        thread.start();
        try {
            Thread.sleep(100);
        } catch (Exception ex) {
        }
        thread.interrupt();
    }

    static class MyTask implements Runnable {
        @Override
        public void run() {
            while (true) {
                if (Thread.interrupted()) {
                    break;
                }
                System.out.println(Thread.currentThread() + " is running...");
            }
            System.out.println("當(dāng)前中斷標(biāo)志位狀態(tài):" + Thread.currentThread().isInterrupted());
        }
    }
}
image.png

InterruptedException

調(diào)用Thread.sleep()時(shí)都需要捕獲InterruptedException異常。這個(gè)異常的作用是什么?
如果目標(biāo)線程正在執(zhí)行阻塞方法(sleep、join),而其他線程恰好調(diào)用了目標(biāo)線程的interrupt方法試圖中斷目標(biāo)線程,sleep、join這類阻塞方法會檢查線程的中斷標(biāo)志位,并拋出InterruptedException異常。

阻塞方法為何拋出InterruptedException

@Override
public void run() {
    while (true) {
        if (Thread.interrupted()) {
            break;
        }
        // point 1 : 阻塞方法前邏輯
        try {
            // point 2 : 阻塞方法中
            Thread.sleep(10*000*000);
        } catch(InterruptedException ex) {
            // 執(zhí)行清除邏輯
        }
        // point 3 :阻塞方法后邏輯
    }
}

前文提到過,interrupt的線程中斷機(jī)制是由發(fā)起線程將目標(biāo)線程的中斷標(biāo)志位置為true,至于是否執(zhí)行線程的中斷由目標(biāo)線程決定。
以上面代碼為例,如果目標(biāo)線程正在執(zhí)行sleep方法而線程阻塞,必須在10000000時(shí)間完成且并執(zhí)行完后續(xù)邏輯,直至循環(huán)里下次interrupted()判斷后才能中斷線程。顯然這不是我們希望看到的,所以阻塞方法會判斷中斷標(biāo)志位,一旦出現(xiàn)中斷的命令就會拋出異常,直接終止阻塞邏輯。

InterruptedException清空中斷標(biāo)志位

拋出InterruptedException異常也會清除中斷標(biāo)志位,如果想要繼續(xù)保留中斷標(biāo)志位的狀態(tài),可以手動觸發(fā)中斷標(biāo)志,代碼如下:

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  Thread.currentThread().interrupt(); 
  throw new RuntimeException(ex);
}

總結(jié)

要想理解java線程中斷的原理,重點(diǎn)就是要掌握中斷標(biāo)志位的使用細(xì)節(jié),其他的邏輯都是圍繞中斷標(biāo)志位設(shè)計(jì)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 線程的中斷 使用interrupt()中斷線程 當(dāng)一個(gè)線程運(yùn)行時(shí),另一個(gè)線程可以調(diào)用對應(yīng)的Thread對象的int...
    史路比閱讀 438評論 1 1
  • 單任務(wù) 單任務(wù)的特點(diǎn)是排隊(duì)執(zhí)行,也就是同步,就像再cmd輸入一條命令后,必須等待這條命令執(zhí)行完才可以執(zhí)行下一條命令...
    Steven1997閱讀 1,357評論 0 6
  • 一、wait--notify--sleep Object obj = new Object(); obj.wait...
    fe0180bd6eaf閱讀 392評論 0 1
  • 轉(zhuǎn)自:https://www.cnblogs.com/onlywujun/p/3565082.html 中斷線程 ...
    mayiwoaini閱讀 722評論 0 1
  • 1、概述 Java 給多線程編程提供了內(nèi)置的支持。 一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多...
    高丕基閱讀 556評論 0 8

友情鏈接更多精彩內(nèi)容