Java多線程(二)

Java多線程(二)

上一篇“Java多線程(一)”主要討論的是線程的創(chuàng)建沙咏,本章主要討論停止線程

1.概述

停止一個(gè)線程意味著在線程處理完任務(wù)之前停掉正在做的操作撕捍,也就是放棄當(dāng)前的操作钞翔。雖然這看起來很簡(jiǎn)單黑忱,但是必須做好防范措施叶圃,以便達(dá)到預(yù)期的效果袄膏。
在java中有以下3中方法可以終止正在運(yùn)行的線程:

  • (1)使用退出標(biāo)志,使線程正常退出掺冠,也就是當(dāng)run方法完成后線程終止沉馆。
  • (2)使用stop方法強(qiáng)行終止線程,但是不推薦使用這個(gè)方法德崭,因?yàn)榇朔椒ㄒ呀?jīng)過時(shí)悍及。
  • (3)使用interrupt方法中斷線程。

2.使用stop()停止線程

使用stop()停止線程是非常暴力的接癌,但不推薦用它,雖然它確實(shí)可以停止一個(gè)正在運(yùn)行的線程扣讼,但這個(gè)方法是不安全的缺猛,而且已經(jīng)是被棄用作廢的,在將來的java版本中,這個(gè)方法將不可用或不被支持荔燎。

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 5000; i++) {
            System.out.println("i=" + (i + 1));
        }
    }

    public static void main(String[] args) {
        try {
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(10);
            myThread.stop();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

JDK源碼中將stop()標(biāo)識(shí)為過時(shí)(Deprecated):

 @Deprecated
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if (this != Thread.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
...

stop()方法的不良后果

1)調(diào)用 stop() 方法會(huì)立刻停止 run() 方法中剩余的全部工作耻姥,包括在 catch 或 finally 語句中的,并拋出ThreadDeath異常(通常情況下此異常不需要顯示的捕獲)有咨,因此可能會(huì)導(dǎo)致一些清理性的工作的得不到完成琐簇,如文件,數(shù)據(jù)庫等的關(guān)閉座享。
2)調(diào)用 stop() 方法會(huì)立即釋放該線程所持有的所有的鎖婉商,導(dǎo)致數(shù)據(jù)得不到同步,出現(xiàn)數(shù)據(jù)不一致的問題渣叛。

3.使用interrupt方法中斷線程

tips:使用interrupt()方法僅僅是在當(dāng)前線程中打了一個(gè)停止的標(biāo)記丈秩,并不是真正的停止線程。
所以使用interrupt()方法中斷線程還需要結(jié)合判斷線程是不是停止的淳衙,如果判斷線程是中斷狀態(tài)再停止線程蘑秽。Java的SDK提供了兩種方法來判斷線程是否停止:

  • 1)this.interrupted():測(cè)試當(dāng)前線程是否已經(jīng)是中斷狀態(tài),執(zhí)行后具有將狀態(tài)標(biāo)志清除為false的功能箫攀。
  • 2)this.isInterrupted():測(cè)試線程Thread對(duì)象是否已經(jīng)是中斷狀態(tài)肠牲,但不清除狀態(tài)標(biāo)志。

3.1 兩種判斷線程停止?fàn)顟B(tài)方式的區(qū)別

public static void main(String[] args) {
        try {
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(100);
            myThread.interrupt();
            System.out.println("是否停止1:"+myThread.interrupted());
            System.out.println("是否停止1:"+myThread.interrupted());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

輸出結(jié)果:

是否停止1:false
是否停止1:false

代碼執(zhí)行myThread.interrupt()給myThread線程打上停止標(biāo)記靴跛。然后用interrupted()來判斷線程狀態(tài)缀雳。但從輸出結(jié)果來看,線程并未停止汤求,這也就印證了interrupted()的解釋:測(cè)試當(dāng)前線程是否已經(jīng)中斷俏险,當(dāng)前線程是main線程,從未中斷過扬绪。
將上面的代碼稍作修改:

public class TestInterrupt {
    public static void main(String[] args) {
        try {
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(100);
//            myThread.interrupt();
            Thread.currentThread().interrupt();
            System.out.println("是否停止1:"+Thread.interrupted());
            System.out.println("是否停止1:"+Thread.interrupted());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

輸出結(jié)果:

是否停止1:true
是否停止1:false

修改后的代碼使用Thread.currentThread().interrupt();中斷了main線程竖独,并且第一次執(zhí)行interrupted()的結(jié)果為true,第二次執(zhí)行的結(jié)果為false挤牛,這也印證了interrupted()具有將狀態(tài)標(biāo)志清除的功能莹痢。
再來看看isInterrupted()方法:

    public static void main(String[] args) {
          MyThread myThread = new MyThread();
          myThread.start();
          myThread.interrupt();
          System.out.println("是否停止1:"+myThread.isInterrupted());
          System.out.println("是否停止1:"+myThread.isInterrupted());
    }

輸出結(jié)果:

是否停止1:true
是否停止1:true

從輸出結(jié)果可以看到,方法isInterrupted()并未清除狀態(tài)標(biāo)志墓赴,所以打印了兩個(gè)true竞膳。

3.2 中斷線程的方法——異常法

public class InterruptMyThread extends Thread {
    @Override
    public void run() {
        super.run();
        try{
            for(int i=0;i<50000;i++){
                if(this.interrupted()){
                    System.out.println("線程是停止?fàn)顟B(tài)了。诫硕。坦辟。。");
                    throw new InterruptedException();
                }
                System.out.println(i);
            }
        }catch (InterruptedException e){
            System.out.println("線程停止章办,跳出for循環(huán)锉走,進(jìn)入catch");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            InterruptMyThread interruptMyThread = new InterruptMyThread();
            interruptMyThread.start();
            Thread.sleep(1000);
            interruptMyThread.interrupt();
        } catch (InterruptedException e) {
            System.out.println("main catch~");
            e.printStackTrace();
        }
    }
}

輸出結(jié)果:

線程是停止?fàn)顟B(tài)了滨彻。。挪蹭。亭饵。
線程停止,跳出for循環(huán)梁厉,進(jìn)入catch
java.lang.InterruptedException
    at com.panda.thread.stop.interrupt.InterruptMyThread.run(InterruptMyThread.java:11)

3.3 中斷線程的方法——return

將方法interrupt()與return結(jié)合使用也能實(shí)現(xiàn)停止線程的效果辜羊。

public class InterruptThreadByReturn extends Thread {
   @Override
   public void run() {
       super.run();
       while (true){
           if(this.isInterrupted()){
               System.out.println("線程停止了!");
               return;
           }
           System.out.println("timer="+System.currentTimeMillis());
       }
   }

   public static void main(String[] args) throws InterruptedException {
       InterruptThreadByReturn interruptThreadByReturn = new InterruptThreadByReturn();
       interruptThreadByReturn.start();
       Thread.sleep(2000);
       interruptThreadByReturn.interrupt();
   }
}

輸出結(jié)果:

...
timer=1611474998138
timer=1611474998138
timer=1611474998138
timer=1611474998138
線程停止了!

不過還是建議使用“異常法”來實(shí)現(xiàn)線程的停止,因?yàn)榭梢栽赾atch塊中可以對(duì)異常的信息進(jìn)行相關(guān)的處理词顾,而且使用異常流能更好八秃、更方便地控制程序的運(yùn)行流程。

3.4 在沉睡中停止

如果在sleep狀態(tài)下停止某一線程计技,會(huì)拋出InterruptedException異常喜德,并清除停止?fàn)顟B(tài)值。

public class InterruptThreadinSleep extends Thread{
    @Override
    public void run() {
        super.run();
        try{
            System.out.println("begin");
            Thread.sleep(200000);
            System.out.println("end");
        }catch (InterruptedException e){
            System.out.println("進(jìn)入catch--"+this.isInterrupted());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try{
            InterruptThreadinSleep interruptThreadinSleep = new InterruptThreadinSleep();
            interruptThreadinSleep.start();
            Thread.sleep(200);
            interruptThreadinSleep.interrupt();
        }catch (InterruptedException e){
            System.out.println("main catch!");
            e.printStackTrace();
        }
    }
}

輸出結(jié)果:

begin
進(jìn)入catch--false
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.panda.thread.stop.interrupt.InterruptThreadinSleep.run(InterruptThreadinSleep.java:9)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末垮媒,一起剝皮案震驚了整個(gè)濱河市舍悯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌睡雇,老刑警劉巖萌衬,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異它抱,居然都是意外死亡秕豫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門观蓄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來混移,“玉大人,你說我怎么就攤上這事侮穿「杈叮” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵亲茅,是天一觀的道長(zhǎng)回铛。 經(jīng)常有香客問我,道長(zhǎng)克锣,這世上最難降的妖魔是什么茵肃? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮袭祟,結(jié)果婚禮上验残,老公的妹妹穿的比我還像新娘。我一直安慰自己巾乳,他們只是感情好胚膊,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布故俐。 她就那樣靜靜地躺著,像睡著了一般紊婉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辑舷,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天喻犁,我揣著相機(jī)與錄音,去河邊找鬼何缓。 笑死肢础,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碌廓。 我是一名探鬼主播传轰,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谷婆!你這毒婦竟也來了慨蛙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤纪挎,失蹤者是張志新(化名)和其女友劉穎期贫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體异袄,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡通砍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烤蜕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片封孙。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖讽营,靈堂內(nèi)的尸體忽然破棺而出虎忌,到底是詐尸還是另有隱情,我是刑警寧澤斑匪,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布呐籽,位于F島的核電站,受9級(jí)特大地震影響蚀瘸,放射性物質(zhì)發(fā)生泄漏狡蝶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一贮勃、第九天 我趴在偏房一處隱蔽的房頂上張望贪惹。 院中可真熱鬧,春花似錦寂嘉、人聲如沸奏瞬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硼端。三九已至并淋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間珍昨,已是汗流浹背县耽。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留镣典,地道東北人兔毙。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像兄春,于是被迫代替她去往敵國和親澎剥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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