終止線程的2種方法。標記法和中斷

引言

在原來的jdk版本中:
提供了暫停,恢復,終止線程的方法,分別是suspend(),resume(),stop();
可是它們都存在缺陷,好比暫停suspend()方法在調用後,線程不會釋放資源(好比:鎖),而是佔有着資源進入睡眠狀態。stop()方法在調用後,一般不能保證線程的資源正常的釋放,由於他根本沒有給予線程釋放資源的機會。
正由於這些方法帶來的不良影響,使得它們被廢除。java

替代

然而聰明的程序員仍是想出來了替代上述api的方法,程序員

原始api 替代方案
暫停和恢復 等待-通知機制
終止 標記法和中斷法

終止線程-法一:標記法

經過置標記爲相反的布爾值,來終止線程web

代碼:

package Interrupt;

public class InterruptThread4 {
    public static void main(String args[]) throws InterruptedException {
        ThreadTest t1=new ThreadTest();
        t1.start();
        Thread.sleep(1000);
        System.out.println(System.currentTimeMillis());
        t1.stopMe();

    }
    static class ThreadTest extends Thread{
        private boolean stopMe=false;

        public void stopMe() {
            this.stopMe = true;
        }

        @Override
        public void run() {
            while(true){
                if(stopMe){
                    System.out.println("interrupt!");
                    break;
                }
                try {
                    System.out.println("t1 sleep");
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Thread.yield();
            }
            System.out.println(System.currentTimeMillis());
        }
    }
}

結果:

t1 sleep
1501152592588
interrupt!
1501152596589api

現象:

經過打印的時間戳對比發現,發出中斷信號和線程中斷相隔的時間爲5s,這正是線程休眠的時間。因此經過標誌來中斷線程,假設線程中有sleep()和wait()方法,它達不到當即終止的做用,必須等線程恢復正常運行或者喚醒後才能終止。jvm

終止線程-法二:中斷法

Thread中斷是經過內部的標記字段來進行的,線程中斷並非使線程馬上退出,而是發送給線程一個通知,至於目標線程接到通知如何處理是由線程本身決定。這是和stop()方法強行退出是不一樣的ide

api

在演示實例以前,先來了解下Thread類中斷的apisvg

api 含義
public void interrupt() 中斷線程
public boolean isInterrupt() 判斷線程是否中斷
public static boolean interrupted 判斷線程是否中斷,而且清除當前中斷狀態

代碼

package Interrupt;

public class InterruptThread3 {
    public static void main(String args[]) throws InterruptedException {
        Thread t1=new Thread(){
            @Override
            public void run() {
                while(true){
                    if(Thread.currentThread().isInterrupted()){
                        System.out.println("interrupt!");
                        break;
                    }
                    try {
                        System.out.println("t1 sleep");
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        //設置中斷狀態
                        Thread.currentThread().interrupt();
                    }
                    Thread.yield();
                }
                System.out.println(System.currentTimeMillis());
            }
        };
        t1.start();
        Thread.sleep(1000);
        System.out.println(System.currentTimeMillis());
        t1.interrupt();
    }
}

結果

1501153532961
java.lang.InterruptedException: sleep interrupted
interrupt!
at java.lang.Thread.sleep(Native Method)
1501153532963
at Interrupt.InterruptThread3$1.run(InterruptThread3.java:15)this

現象

發現interrupt()幾乎能夠達到當即中斷的效果,可是線程必須捕獲InterruptedException異常這是前提條件。不然線程會永遠的執行下去。
至於在catch代碼塊中爲何要經過Thread.currentThread().interrupt();來重置中斷狀態,由於當jvm由於sleep(),wait()等須要捕獲異常的方法被中斷時,在拋出InterruptedException以前,它會先清除掉線程的中斷標誌位,使得isInterrupted()返回false;spa

中斷的兩種方法對比

若是線程中有wait()和sleep()等方法,用中斷法來終止線程效果更好。
由於若是線程長久的等待下去,而沒有任何其餘線程對其喚醒或者長期的睡眠下去,標誌法根本沒法中斷,而中斷法能夠當即中斷。線程

最後的兩點很是重要:

a.要使用interrupt()方法來中斷線程,必定要在方法裏捕獲InterruptedException。
b.若是由於wait(),或sleep()等須要捕獲InterruptedException的方法被中斷時,jvm會在拋出異常以前先清除中斷標記位,使得isInterrupted()返回爲false。素以咱們要在判斷以前先從新設置好標記位

很久沒寫博客了,閃~

相關文章
相關標籤/搜索