線程的停止和中斷

停止一個線程意味著在任務(wù)處理完任務(wù)之前停掉正在做的操作柒瓣,也就是放棄當(dāng)前的操作喳魏。停止一個線程可以用Thread.stop()方法卖毁,但最好不要用它羡藐。雖然它確實可以停止一個正在運行的線程叹阔,但是這個方法是不安全的,而且是已被廢棄的方法传睹。
在java中有以下3種方法可以終止正在運行的線程:

①使用退出標(biāo)志,使線程正常退出岸晦,也就是當(dāng)run方法完成后線程終止欧啤。

②使用stop方法強(qiáng)行終止,但是不推薦這個方法启上,因為stop和suspend及resume一樣都是過期作廢的方法邢隧。

③使用interrupt方法中斷線程。

1.停止不了的線程

interrupt()方法的使用效果并不像for+break語句那樣冈在,馬上就停止循環(huán)倒慧。調(diào)用interrupt方法是在當(dāng)前線程中打了一個停止標(biāo)志,并不是真的停止線程包券。

public class MyThread extends Thread {
    public void run(){
        super.run();
try {
            for(int i=0; i<500000; i++){
            System.out.println("i="+(i+1));
        }
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
    }
}

輸出結(jié)果:

...
i=499994
i=499995
i=499996
i=499997
i=499998
i=499999
i=500000

2. 判斷線程是否停止?fàn)顟B(tài)

Thread.java類中提供了兩種方法:
this.interrupted(): 測試當(dāng)前線程是否已經(jīng)中斷纫谅;
this.isInterrupted(): 測試線程是否已經(jīng)中斷;
其中this.interrupted()方法的解釋:測試當(dāng)前線程是否已經(jīng)中斷溅固,當(dāng)前線程是指運行this.interrupted()方法的線程付秕。

public class MyThread extends Thread {
    public void run(){
        super.run();
        for(int i=0; i<500000; i++){
            i++;
//            System.out.println("i="+(i+1));
        }
         try {
            Thread.sleep(2000);
            thread.interrupt();

            System.out.println("stop 1??" + thread.interrupted());
            System.out.println("stop 2??" + thread.interrupted());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Run {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
    }
}

運行結(jié)果:

stop 1??false
stop 2??false

類Run.java中雖然是在thread對象上調(diào)用以下代碼:thread.interrupt(), 后面又使用

System.out.println("stop 1??" + thread.interrupted());
System.out.println("stop 2??" + thread.interrupted());  

來判斷thread對象所代表的線程是否停止,但從控制臺打印的結(jié)果來看侍郭,線程并未停止询吴,這也證明了interrupted()方法的解釋,測試當(dāng)前線程是否已經(jīng)中斷亮元。這個當(dāng)前線程是main猛计,它從未中斷過,所以打印的結(jié)果是兩個false

如何使main線程產(chǎn)生中斷效果呢爆捞?

public class Run2 {
    public static void main(String args[]){
        Thread.currentThread().interrupt();
        System.out.println("stop 1??" + Thread.interrupted());
        System.out.println("stop 2??" + Thread.interrupted());

        System.out.println("End");
    }
}    

運行效果為:

stop 1??true
stop 2??false
End

方法interrupted()的確判斷出當(dāng)前線程是否是停止?fàn)顟B(tài)奉瘤。但為什么第2個布爾值是false呢? 官方幫助文檔中對interrupted方法的解釋:
測試當(dāng)前線程是否已經(jīng)中斷嵌削。線程的中斷狀態(tài)由該方法清除毛好。 換句話說,如果連續(xù)兩次調(diào)用該方法苛秕,則第二次調(diào)用返回false肌访。

下面來看一下isInterrupted()方法。

public class Run3 {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
        thread.interrupt();
        System.out.println("stop 1??" + thread.isInterrupted());
        System.out.println("stop 2??" + thread.isInterrupted());
    }
}

運行結(jié)果:

stop 1??true
stop 2??true

isInterrupted()并為清除狀態(tài)艇劫,所以打印了兩個true吼驶。

3. 能停止的線程--異常法

有了前面學(xué)習(xí)過的知識點,就可以在線程中用for語句來判斷一下線程是否是停止?fàn)顟B(tài),如果是停止?fàn)顟B(tài)蟹演,則后面的代碼不再運行即可:

public class MyThread extends Thread {
    public void run(){
        super.run();
        for(int i=0; i<500000; i++){
            if(this.interrupted()) {
                System.out.println("線程已經(jīng)終止风钻, for循環(huán)不再執(zhí)行");
                break;
            }
            System.out.println("i="+(i+1));
        }
    }
}

public class Run {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

運行結(jié)果:

...
i=202053
i=202054
i=202055
i=202056

線程已經(jīng)終止, for循環(huán)不再執(zhí)行
上面的示例雖然停止了線程酒请,但如果for語句下面還有語句骡技,還是會繼續(xù)運行的⌒叻矗看下面的例子:

public class MyThread extends Thread {
    public void run(){
        super.run();
        for(int i=0; i<500000; i++){
            if(this.interrupted()) {
                System.out.println("線程已經(jīng)終止布朦, for循環(huán)不再執(zhí)行");
                break;
            }
            System.out.println("i="+(i+1));
        }

        System.out.println("這是for循環(huán)外面的語句,也會被執(zhí)行");
    }
}

使用Run.java執(zhí)行的結(jié)果是:

...
i=180136
i=180137
i=180138
i=180139

線程已經(jīng)終止昼窗, for循環(huán)不再執(zhí)行
這是for循環(huán)外面的語句是趴,也會被執(zhí)行
如何解決語句繼續(xù)運行的問題呢? 看一下更新后的代碼:

public class MyThread extends Thread {
    public void run(){
        super.run();
        try {
            for(int i=0; i<500000; i++){
                if(this.interrupted()) {
                    System.out.println("線程已經(jīng)終止澄惊, for循環(huán)不再執(zhí)行");
                        throw new InterruptedException();
                }
                System.out.println("i="+(i+1));
            }

            System.out.println("這是for循環(huán)外面的語句唆途,也會被執(zhí)行");
        } catch (InterruptedException e) {
            System.out.println("進(jìn)入MyThread.java類中的catch了。掸驱。肛搬。");
            e.printStackTrace();
        }
    }
}

使用Run.java運行的結(jié)果如下:

...
i=203798
i=203799
i=203800
線程已經(jīng)終止, for循環(huán)不再執(zhí)行
進(jìn)入MyThread.java類中的catch了亭敢。滚婉。。
java.lang.InterruptedException
    at thread.MyThread.run(MyThread.java:13)

4. 在沉睡中停止

如果線程在sleep()狀態(tài)下停止線程帅刀,會是什么效果呢让腹?

public class MyThread extends Thread {
    public void run(){
        super.run();

        try {
            System.out.println("線程開始。扣溺。骇窍。");
            Thread.sleep(200000);
            System.out.println("線程結(jié)束。");
        } catch (InterruptedException e) {
            System.out.println("在沉睡中被停止, 進(jìn)入catch锥余, 調(diào)用isInterrupted()方法的結(jié)果是:" + this.isInterrupted());
            e.printStackTrace();
        }

    }
}

使用Run.java運行的結(jié)果是:

線程開始腹纳。。驱犹。
在沉睡中被停止, 進(jìn)入catch嘲恍, 調(diào)用isInterrupted()方法的結(jié)果是:false
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at thread.MyThread.run(MyThread.java:12)

從打印的結(jié)果來看, 如果在sleep狀態(tài)下停止某一線程雄驹,會進(jìn)入catch語句佃牛,并且清除停止?fàn)顟B(tài)值,使之變?yōu)閒alse医舆。

前一個實驗是先sleep然后再用interrupt()停止俘侠,與之相反的操作在學(xué)習(xí)過程中也要注意:

public class MyThread extends Thread {
    public void run(){
        super.run();
        try {
            System.out.println("線程開始象缀。。爷速。");
            for(int i=0; i<10000; i++){
                System.out.println("i=" + i);
            }
            Thread.sleep(200000);
            System.out.println("線程結(jié)束央星。");
        } catch (InterruptedException e) {
             System.out.println("先停止,再遇到sleep惫东,進(jìn)入catch異常");
            e.printStackTrace();
        }

    }
}

public class Run {
    public static void main(String args[]){
        Thread thread = new MyThread();
        thread.start();
        thread.interrupt();
    }
}

運行結(jié)果:

i=9998
i=9999
先停止莉给,再遇到sleep,進(jìn)入catch異常
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at thread.MyThread.run(MyThread.java:15)

5. 能停止的線程---暴力停止

使用stop()方法停止線程則是非常暴力的廉沮。

public class MyThread extends Thread {
    private int i = 0;
    public void run(){
        super.run();
        try {
            while (true){
                System.out.println("i=" + i);
                i++;
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Run {
    public static void main(String args[]) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();
        Thread.sleep(2000);
        thread.stop();
    }
}

運行結(jié)果:

i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9

Process finished with exit code 0

6.方法stop()與java.lang.ThreadDeath異常
調(diào)用stop()方法時會拋出java.lang.ThreadDeath異常禁谦,但是通常情況下,此異常不需要顯示地捕捉废封。

public class MyThread extends Thread {
    private int i = 0;
    public void run(){
        super.run();
        try {
            this.stop();
        } catch (ThreadDeath e) {
            System.out.println("進(jìn)入異常catch");
            e.printStackTrace();
        }
    }
}

public class Run {
    public static void main(String args[]) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();
    }
}

stop()方法以及作廢,因為如果強(qiáng)制讓線程停止有可能使一些清理性的工作得不到完成丧蘸。另外一個情況就是對鎖定的對象進(jìn)行了解鎖漂洋,導(dǎo)致數(shù)據(jù)得不到同步的處理,出現(xiàn)數(shù)據(jù)不一致的問題力喷。

7. 釋放鎖的不良后果

使用stop()釋放鎖將會給數(shù)據(jù)造成不一致性的結(jié)果刽漂。如果出現(xiàn)這樣的情況,程序處理的數(shù)據(jù)就有可能遭到破壞弟孟,最終導(dǎo)致程序執(zhí)行的流程錯誤贝咙,一定要特別注意:

public class SynchronizedObject {
    private String name = "a";
    private String password = "aa";

    public synchronized void printString(String name, String password){
        try {
            this.name = name;
            Thread.sleep(100000);
            this.password = password;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

public class MyThread extends Thread {
    private SynchronizedObject synchronizedObject;
    public MyThread(SynchronizedObject synchronizedObject){
        this.synchronizedObject = synchronizedObject;
    }

    public void run(){
        synchronizedObject.printString("b", "bb");
    }
}

public class Run {
    public static void main(String args[]) throws InterruptedException {
        SynchronizedObject synchronizedObject = new SynchronizedObject();
        Thread thread = new MyThread(synchronizedObject);
        thread.start();
        Thread.sleep(500);
        thread.stop();
        System.out.println(synchronizedObject.getName() + "  " + synchronizedObject.getPassword());
    }
}

輸出結(jié)果:

b  aa

由于stop()方法以及在JDK中被標(biāo)明為“過期/作廢”的方法,顯然它在功能上具有缺陷拂募,所以不建議在程序張使用stop()方法庭猩。

8. 使用return停止線程

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

public class MyThread extends Thread {
    public void run(){
        while (true){
            if(this.isInterrupted()){
                System.out.println("線程被停止了!");
                return;
            }
            System.out.println("Time: " + System.currentTimeMillis());
        }
    }
}

public class Run {
    public static void main(String args[]) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();
        Thread.sleep(2000);
        thread.interrupt();
    }
}

輸出結(jié)果:

...
Time: 1467072288503
Time: 1467072288503
Time: 1467072288503
線程被停止了陈症!

不過還是建議使用“拋異嘲”的方法來實現(xiàn)線程的停止,因為在catch塊中還可以將異常向上拋录肯,使線程停止事件得以傳播趴腋。

https://www.cnblogs.com/greta/p/5624839.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市论咏,隨后出現(xiàn)的幾起案子优炬,更是在濱河造成了極大的恐慌,老刑警劉巖厅贪,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蠢护,死亡現(xiàn)場離奇詭異,居然都是意外死亡卦溢,警方通過查閱死者的電腦和手機(jī)糊余,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門秀又,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贬芥,你說我怎么就攤上這事吐辙。” “怎么了蘸劈?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵昏苏,是天一觀的道長。 經(jīng)常有香客問我威沫,道長贤惯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任棒掠,我火速辦了婚禮孵构,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烟很。我一直安慰自己颈墅,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布雾袱。 她就那樣靜靜地躺著恤筛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芹橡。 梳的紋絲不亂的頭發(fā)上毒坛,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機(jī)與錄音林说,去河邊找鬼煎殷。 笑死,一個胖子當(dāng)著我的面吹牛腿箩,可吹牛的內(nèi)容都是我干的蝌数。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼度秘,長吁一口氣:“原來是場噩夢啊……” “哼顶伞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起剑梳,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤唆貌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后垢乙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锨咙,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年追逮,在試婚紗的時候發(fā)現(xiàn)自己被綠了酪刀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粹舵。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖骂倘,靈堂內(nèi)的尸體忽然破棺而出眼滤,到底是詐尸還是另有隱情,我是刑警寧澤历涝,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布诅需,位于F島的核電站驮配,受9級特大地震影響崔涂,放射性物質(zhì)發(fā)生泄漏奈应。R本人自食惡果不足惜梅猿,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爷辱。 院中可真熱鬧鳄乏,春花似錦唠亚、人聲如沸蚪战。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屎勘。三九已至,卻和暖如春居扒,著一層夾襖步出監(jiān)牢的瞬間概漱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工喜喂, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留瓤摧,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓玉吁,卻偏偏與公主長得像照弥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子进副,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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