Java并發(fā)編程之線程篇之線程中斷(三)

IMG_0141.JPG

前言

在上篇文章Java并發(fā)編程之線程篇之線程簡介(二)中我們基本了解了如何創(chuàng)建一個(gè)線程并執(zhí)行相應(yīng)任務(wù)表窘,但是并沒有提到如何中斷一個(gè)線程扳碍。例如:我們有一個(gè)下載程序線程,該線程在沒有下載成功之前是不會(huì)退出的,假如這個(gè)時(shí)候用戶不想下載了领突,那我們該如何中斷這個(gè)下載線程呢?下面我們就來學(xué)習(xí)如何正確的中斷一個(gè)線程吧案怯。

對于過時(shí)的suspend()君旦、resume()和stop()方法,這里就不介紹了嘲碱,有興趣的小伙伴可以查閱相關(guān)資料金砍。

Java線程的中斷機(jī)制

當(dāng)我們需要中斷某個(gè)線程時(shí),看似我們只需要調(diào)一個(gè)中斷方法(調(diào)用之后線程就不執(zhí)行了)就行了麦锯。但是Java中并沒有提供一個(gè)實(shí)際的方法來中斷某個(gè)線程(不考慮過時(shí)的stop()方法)恕稠,只提供了一個(gè)中斷標(biāo)志位,來表示線程在運(yùn)行期間已經(jīng)被其他線程進(jìn)行了中斷操作离咐。也就是說線程只有通過自身來檢查這個(gè)標(biāo)志位谱俭,來判斷自己是否被中斷了。在Java中提供了三個(gè)方法來設(shè)置或判斷中斷標(biāo)志位宵蛀,具體方法如下所示:

   //類方法昆著,設(shè)置當(dāng)前線程中標(biāo)志位
   public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // 設(shè)置中斷標(biāo)志位
                b.interrupt(this);
                return;
            }
        }
        interrupt0();//設(shè)置中斷標(biāo)志位
    }

    //靜態(tài)方法,判斷當(dāng)前線程是否中斷术陶,清除中斷標(biāo)志位
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    //類方法凑懂,判斷當(dāng)前線程是否中斷,不清除中斷標(biāo)志位
    public boolean isInterrupted() {
        return isInterrupted(false);
    }

在上述方法中梧宫,我們可以通過interrupt()來設(shè)置相應(yīng)線程中斷標(biāo)志接谨,通過Thread類靜態(tài)方法interrupted()和類方法isInterrupted()來判斷對應(yīng)線程是否被其他線程中斷。其中interrupted()與isInterrupted()方法的主要區(qū)別如下:

  • interrupted 判斷當(dāng)前線程是否中斷(如果是中斷塘匣,則會(huì)清除中斷的狀態(tài)標(biāo)志脓豪,也就是如果中斷了線程,第一次調(diào)用這個(gè)方法返回true忌卤,第二次繼續(xù)調(diào)用則返回false扫夜。
  • isInterrupted 判斷線程是否已經(jīng)中斷(不清除中斷的狀態(tài)標(biāo)志)。

使用interrupt()中斷線程

在上文中驰徊,我們了解了線程的如何設(shè)置中斷標(biāo)志位與如何判斷標(biāo)志位笤闯,那現(xiàn)在我們來使用interrupt()方法來中斷一個(gè)線程。先看下面這個(gè)例子棍厂。

class InterruptDemo {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000000; i++) {
                    System.out.println("i=" + i);
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//輸出結(jié)果:
i=593210
i=593211
i=593212
i=593213
i=593214
i=593215
i=593216

運(yùn)行上述代碼颗味,觀察輸出結(jié)果,我們發(fā)現(xiàn)線程并沒有被終止牺弹,原因是因?yàn)?code>interrupt()方法只會(huì)設(shè)置線程中斷標(biāo)志位浦马,并不會(huì)真正的中斷線程时呀。也就是說我們只有自己來判斷線程是否終止。一般情況下捐韩,當(dāng)我們檢查到線程被中斷(也就是線程標(biāo)志位為true)時(shí)退唠,會(huì)拋出一個(gè)InterruptedException異常,來中斷線程任務(wù)荤胁。具體代碼如下:

class InterruptDemo {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 1000000; i++) {
                        if (Thread.interrupted()) {
                            System.out.println("檢測到線程被中斷");
                            throw new InterruptedException();
                        }
                        System.out.println("i=" + i);
                    }
                } catch (InterruptedException e) {
                    //執(zhí)行你自己的中斷邏輯
                    System.out.println("線程被中斷了瞧预,你自己判斷該如何處理吧");
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//輸出結(jié)果:
i=218626
i=218627
i=218628
i=218629
i=218630
檢測到線程被中斷
線程被中斷了,你自己判斷該如何處理吧
java.lang.InterruptedException
    at InterruptDemo$1.run(InterruptDemo.java:18)
    at java.base/java.lang.Thread.run(Thread.java:835)

在上述代碼中仅政,我們通過在線程中判斷Thread.interrupted()來判斷線程是否中斷垢油,當(dāng)線程被中斷后,我們拋出InterruptedException異常圆丹。然后通過try/catch來捕獲該異常來執(zhí)行我們自己的中斷邏輯滩愁。當(dāng)然我們也可以通過Thread.currentThread().isInterrupted()來判斷。這兩個(gè)方法的區(qū)別已經(jīng)在上文介紹了辫封,這里就不過多的介紹了硝枉。

中斷線程的另一種方式

在上文中提到的使用interrupt()來中斷線程以外,我們還可以通過一個(gè)boolean來控制是否中斷線程倦微。具體例子如下所示:

class InterruptDemo {

    public static void main(String[] args) {
        RunnableA runnableA = new RunnableA();
        Thread thread = new Thread(runnableA);
        thread.start();
        try {
            Thread.sleep(2000);
            runnableA.interruptThread();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class RunnableA implements Runnable {
        boolean isInterrupt;

        @Override
        public void run() {
            for (int i = 0; i < 1000000; i++) {
                if (!isInterrupt) {
                    System.out.println("i=" + i);
                } else {
                    System.out.println("線程結(jié)束運(yùn)行了");
                    break;
                }
            }
        }

        void interruptThread() {
            isInterrupt = true;
        }
    }
}
//輸出結(jié)果:
i=240399
i=240400
i=240401
i=240402
i=240403
i=240404
i=240405
線程結(jié)束運(yùn)行了

上述代碼中妻味,我們通過判斷isInterrupt的值來判斷是否跳出循環(huán)。run()方法的結(jié)束欣福,就標(biāo)志著線程已經(jīng)執(zhí)行完畢了责球。

最后

站在巨人的肩膀上,才能看的更遠(yuǎn)~

  • 《Java并發(fā)編程的藝術(shù)》
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拓劝,一起剝皮案震驚了整個(gè)濱河市雏逾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郑临,老刑警劉巖栖博,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異厢洞,居然都是意外死亡仇让,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門犀变,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妹孙,“玉大人秋柄,你說我怎么就攤上這事获枝。” “怎么了骇笔?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵省店,是天一觀的道長嚣崭。 經(jīng)常有香客問我,道長懦傍,這世上最難降的妖魔是什么雹舀? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮粗俱,結(jié)果婚禮上说榆,老公的妹妹穿的比我還像新娘。我一直安慰自己寸认,他們只是感情好签财,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著偏塞,像睡著了一般唱蒸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灸叼,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天神汹,我揣著相機(jī)與錄音,去河邊找鬼古今。 笑死屁魏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沧卢。 我是一名探鬼主播蚁堤,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼但狭!你這毒婦竟也來了披诗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤立磁,失蹤者是張志新(化名)和其女友劉穎呈队,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唱歧,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宪摧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颅崩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片几于。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖沿后,靈堂內(nèi)的尸體忽然破棺而出沿彭,到底是詐尸還是另有隱情,我是刑警寧澤尖滚,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布喉刘,位于F島的核電站瞧柔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏睦裳。R本人自食惡果不足惜造锅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望廉邑。 院中可真熱鬧哥蔚,春花似錦、人聲如沸蛛蒙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宇驾。三九已至倍靡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間课舍,已是汗流浹背塌西。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筝尾,地道東北人捡需。 一個(gè)月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像筹淫,于是被迫代替她去往敵國和親站辉。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容