Thread線程終止interrupt

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

一、終止處于“阻塞狀態”的線程

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

@Override
public 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)循環體之外,就需要額外的添加退出處理,形式如下:

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

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

二、終止處于運行狀態的線程

通過標記方式終止處于運行狀態的線程,其中,包括“中斷標記”和“額外添加標記”

(1)通過“中斷標記”終止線程,形式如下:

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

說明:

isInterrupted()是判斷線程的中斷標記是不是為true,當前線程處于運行狀態,并且我們需要終止它時,可以調用線程的interrupt()方法,使用線程的中斷標記為true,即isInterrupted()會返回true,此時,就會退出while循環。interrupt()并不會終止處于“運行狀態”的線程,它會將線程的中斷標記設為true

(2)通過“額外添加標記”,形式如下:

rivate volatile boolean flag= true;
    protected void stopTask() {
        flag = false;
    }

@Override
public void run() {
    while (flag) {
    // 執行任務...
    }
}

說明:

線程中有一個flag標記,它的默認值是true,并且我們提供stopTask()來設置flag標記,當我們需要終止該線程時,調用該線程的stopTask()方法就可以讓線程退出while循環。其中將flag定義為volatile類型,保證flag的可見性,其他線程通過stopTask()修改了flag之后,本線程能看到修改后的flag的值。

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

@Override
public 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 1
thread is running
t1 (RUNNABLE) loop 2
thread is running
t1 (RUNNABLE) loop 3
thread 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()僅僅返回中斷標記,關于這兩個方法的詳細解釋請看后續文章。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容