Thread執行緒終止interrupt

船頭尺發表於2021-09-09

interrupt()的字面意思是中斷一個執行緒,那麼它是怎麼使用來達到中斷當前執行緒的呢?我們來看幾個例子。

一、終止處於“阻塞狀態”的執行緒

透過中斷方式終止處於阻塞狀態的執行緒,當執行緒由於被呼叫了sleep(),wait(),join()等方法而進入阻塞狀態,此時呼叫執行緒的interrupt()將執行緒的中斷標記為true。由於處於阻塞狀態,中斷標記會被清除,同時產生一個InterruptedException異常,InterruptedException放在適當的位置就能終止執行緒

@Overridepublic void run() {    try {    while (true) {        // 執行任務...
    }
    } catch (InterruptedException ie) {        // 由於產生InterruptedException異常,退出while(true)迴圈,執行緒終止!
    }
}

說明

while(true)中不斷的執行任務,當執行緒處於阻塞狀態時,呼叫執行緒的interrupt()方法會產生InterruptedException中斷,中斷的捕獲在while(true)之外,這樣就退出了while(true)迴圈。

InterruptException的捕獲一定要放在while(true)迴圈體的外面,這樣產生異常時就退出了while(true)迴圈,否則,InterruptExceptionwhile(true)迴圈體之外,就需要額外的新增退出處理,形式如下:

@Overridepublic void run() {    while (true) {        try {            // 執行任務...
        } catch (InterruptedException ie) {        // InterruptedException在while(true)迴圈體內。
        // 當執行緒產生了InterruptedException異常時,while(true)仍能繼續執行!需要手動退出
        break;
        }
     }
}

上面的InterruptedException異常的捕獲是在while(true)中,當產生異常被catch時,仍然在while(true)迴圈體內,要退出while(true)迴圈體,需要額外的執行操作。

二、終止處於執行狀態的執行緒

透過標記方式終止處於執行狀態的執行緒,其中,包括“中斷標記”和“額外新增標記”

(1)透過“中斷標記”終止執行緒,形式如下:

@Overridepublic void run() {    while (!isInterrupted()) {    // 執行任務...
    }
}

說明:

isInterrupted()是判斷執行緒的中斷標記是不是為true,當前執行緒處於執行狀態,並且我們需要終止它時,可以呼叫執行緒的interrupt()方法,使用執行緒的中斷標記為true,即isInterrupted()會返回true,此時,就會退出while迴圈。interrupt()並不會終止處於“執行狀態”的執行緒,它會將執行緒的中斷標記設為true

(2)透過“額外新增標記”,形式如下:

rivate volatile boolean flag= true;    protected void stopTask() {
        flag = false;
    }@Overridepublic void run() {    while (flag) {    // 執行任務...
    }
}

說明:

執行緒中有一個flag標記,它的預設值是true,並且我們提供stopTask()來設定flag標記,當我們需要終止該執行緒時,呼叫該執行緒的stopTask()方法就可以讓執行緒退出while迴圈。其中將flag定義為volatile型別,保證flag的可見性,其他執行緒透過stopTask()修改了flag之後,本執行緒能看到修改後的flag的值。

綜合終止處於“阻塞狀態”和“執行狀態”的終止方式。

@Overridepublic void run() {    try {        // 1. isInterrupted()保證,只要中斷標記為true就終止執行緒。
        while (!isInterrupted()) {        // 執行任務...
        }
     } catch (InterruptedException ie) {        // 2. InterruptedException異常保證,當InterruptedException異常產生時,執行緒被終止。
     }
}

三、終止執行緒的示例

interrupt()常常被用來終止“阻塞狀態”執行緒,參考示例:

class MyThread extends Thread {    public MyThread(String name) {        super(name);
    }    @Override
    public void run() {      try {            int i=0;            while (!isInterrupted())
            {
                System.out.println("thread is running");
                Thread.sleep(100); // 休眠100ms
                i++;
                System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
            }
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");
        }
    }
}public class Hello {    public static void main(String[] args) {        try {
            Thread t1 = new MyThread("t1");  // 新建“執行緒t1”
            System.out.println(t1.getName() +" ("+t1.getState()+") is new.");

            t1.start();                      // 啟動“執行緒t1”
            System.out.println(t1.getName() +" ("+t1.getState()+") is started.");            // 主執行緒休眠300ms,然後主執行緒給t1發“中斷”指令。
            System.out.println("MainThread sleep");
            Thread.sleep(300);
            System.out.println("Thread interrupt");
            t1.interrupt();
            System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");            // 主執行緒休眠300ms,然後檢視t1的狀態。
            System.out.println("MainThread sleep");
            Thread.sleep(300);
            System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

執行結果:

t1 (NEW) is new.
t1 (RUNNABLE) is started.
MainThread sleep
thread is running
t1 (RUNNABLE) loop 1thread is running
t1 (RUNNABLE) loop 2thread is running
t1 (RUNNABLE) loop 3thread is running
Thread interrupt
t1 (TIMED_WAITING) is interrupted.
MainThread sleep
t1 (RUNNABLE) catch InterruptedException.
t1 (TERMINATED) is interrupted now.

結果說明:

(1)主執行緒main中會透過new MyThread("t1")建立執行緒t1,之後透過t1.start()啟動執行緒t1
(2)t1啟動之後,會不斷的檢查他的中斷標記,如果中斷標記為false,則休眠100ms
(3)t1休眠之後會切換到主執行緒main,主執行緒再次執行時,會執行t1.interrupt()中斷執行緒t1。t1收到中斷指令之後,會將t1的中斷標誌設定為false,而且會丟擲InterruptedException異常,在t1的run()方法中,是在迴圈體之外捕獲的異常,因此迴圈被終止。

透過“額外新增標記”的方式終止“執行狀態”的執行緒的示例:

class MyThread extends Thread {    private volatile boolean flag= true;    public void stopTask() {
        flag = false;
    }    public MyThread(String name) {        super(name);
    }    @Override
    public void run() {        synchronized(this) {            try {                int i=0;                while (flag) {
                    Thread.sleep(100); // 休眠100ms
                    i++;
                    System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
                }
            } catch (InterruptedException ie) {
                System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");
            }
        }
    }
}public class Hello {    public static void main(String[] args) {        try {
            MyThread t1 = new MyThread("t1");  // 新建“執行緒t1”
            System.out.println(t1.getName() +" ("+t1.getState()+") is new.");

            t1.start();                      // 啟動“執行緒t1”
            System.out.println(t1.getName() +" ("+t1.getState()+") is started.");            // 主執行緒休眠300ms,然後主執行緒給t1發“中斷”指令。
            Thread.sleep(300);
            System.out.println("stopTask");
            t1.stopTask();
            System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");            // 主執行緒休眠300ms,然後檢視t1的狀態。
            Thread.sleep(300);
            System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
    }
}

interrupted()isInterrupted()都能夠用於檢測物件的“中斷標記”,區別是interrupted()除了返回中斷標記外,它還會清除中斷標記(即將中斷標記設為false),而isInterrupted()僅僅返回中斷標記,關於這兩個方法的詳細解釋請看後續文章。



作者:激情的狼王
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3016/viewspace-2809661/,如需轉載,請註明出處,否則將追究法律責任。

相關文章