java線程如何中斷?Thread interrupt沒有想象那麼簡單?

引子

本來以爲interrupt()後,線程就立刻停止了,其實不是這樣的!!!

interrupt()通知線程應該停止

interrupt()是Thread的實例方法,它通過設置線程中斷狀態,來提示線程應該停止,真正是否停止何時停止取決於程序員;interrupt()時,如果線程在WAITING/TIMED_WAITING狀態(執行了wait()、wait(long)、join()、join(long)、sleep(long))則會清除中斷狀態,拋出InterruptedException,注不要使用stop來中止線程,此方法已不推薦使用,並會帶來狀態一致性問題。

interrupt()改變狀態

Thread a = new Thread(new Runnable() {
            @Override
            public void run() {
                int i=0;
                while(true){

                    System.out.println(Thread.currentThread().isInterrupted()+"--"+(++i));
                }
            }
        });
        a.start();
        a.interrupt();
        System.out.println("線程被中斷了");
線程被中斷了
true--1
true--2
true--3
true--4
true--5
true--6
true--7
...

可以看到,執行了interrupt()後,線程爲中斷狀態,但線程未停止。
一般的,如果接到線程終止,應該停止,如下


                while(true){
                    if(Thread.currentThread().isInterrupted()){  // 通過判斷中止狀態來採取操作
                        break;
                    }
                    System.out.println(Thread.currentThread().isInterrupted()+"--"+(++i));
                }
        

輸出結果,沒有輸出數字

線程被中斷了

waiting/timed_waiting狀態,interrupt()線程拋出異常

線程處在waiting/timed_waiting狀態,interrupt()導致目標線程拋出InterruptedException異常,並清除中斷狀態;

Thread a = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getState()+"-begin-"+Thread.currentThread().isInterrupted()); // 1
                try {
                    Thread.sleep(2000); //7
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getState()+"-end-"+Thread.currentThread().isInterrupted()); //2
                    e.printStackTrace(System.out);
                }
            }
        });
        a.start(); //3
        System.out.println(a.getState()+"--"+a.isInterrupted()); //4
        a.interrupt(); //5
        System.out.println(a.getState()+"--"+a.isInterrupted()); //6

輸出結果有好幾種情況,這是因爲多線程交替執行導致,包括但不限於以下幾種情況


這種情況的執行順序是,345612


RUNNABLE--false  //
RUNNABLE--true
RUNNABLE-begin-true
RUNNABLE-end-false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at test.Test$1.run(Test.java:15)
	at java.lang.Thread.run(Thread.java:745)

這種情況的執行順序是,341562

RUNNABLE--false
RUNNABLE-begin-false
RUNNABLE--true
RUNNABLE-end-false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at test.Test$1.run(Test.java:15)
	at java.lang.Thread.run(Thread.java:745)

這種情況的執行順序是,317456,咱們重點解釋這種情況,a.start()後,接着執行a線程run方法,1輸出false,執行到7,進入timed_waiting狀態,線程切換到主線程執行4,輸出false,執行5後,線程中斷狀態爲true,繼續執行5,輸出true,調度器切換到a線程拋出異常清除中斷狀態,執行2輸出false。

RUNNABLE-begin-false
TIMED_WAITING--false
TIMED_WAITING--true
RUNNABLE-end-false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at test.Test$1.run(Test.java:15)
	at java.lang.Thread.run(Thread.java:745)

interrupt() vs isInterrupted() vs interrupted()

  • public void interrupt()
    • 設置線程狀態,如果線程處在WAITING/TIMED_WAITING狀態,則拋出InterruptedException,並清除中斷狀態;
  • public boolean isInterrupted()
    • 獲取線程中斷狀態;
  • public static boolean interrupted()
    • 獲取當前線程中斷狀態,然後清除中斷狀態,也就是說,如果連續執行兩次,第二次爲false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章