當一個線程運行時,另外一個線程可以直接通過interrupt方法對其設置中斷標志位。
判斷線程是否中斷的2個方法:
// 判斷目標線程是否被中斷,不會清除中斷標記。
Thread.currentThread().isInterrupted()
// 判斷目標線程是否被中斷,會清除中斷標記
Thread.interrupted()
示例1:判斷目標線程是否被中斷,不會清除中斷標記
public class Task2 implements Runnable {@Overridepublic void run() {System.out.println("線程的run方法開始執行");// 判斷線程是否被中斷,不會清除中斷標記if (Thread.currentThread().isInterrupted()) {System.out.println("線程被中斷");}if (!Thread.currentThread().isInterrupted()) {// 因為上面的Thread.currentThread().isInterrupted()不會清除中斷標記// 因此線程保留了中斷標記,所以該循環不會執行,程序不會輸出1-3的數字for (int i = 0; i < 3; i++) {System.out.println("線程運行,i=" + i);}}System.out.println("線程的run方法執行結束");}
}運行上面的測試類Task2InterruptTest,程序運行結果:
線程的run方法開始執行
線程被中斷
線程的run方法執行結束
以上的程序說明,Thread.currentThread().isInterrupted()不會清除中斷標記,因此線程保留了中斷標記,所以該循環不會執行,程序不會輸出1-3的數字。
示例2:判斷目標線程是否被中斷,清除中斷標記
public class Task3 implements Runnable {@Overridepublic void run() {System.out.println("線程的run方法開始執行");// 判斷線程是否被中斷,會清除中斷標記if (Thread.interrupted()) {System.out.println("線程被中斷");}if (!Thread.currentThread().isInterrupted()) {// 因為上面的Thread.interrupted()會清除中斷標記// 因此線程的中斷標記沒有了,線程繼續執行,程序會輸出1-3的數字for (int i = 0; i < 3; i++) {System.out.println("線程運行,i=" + i);}}System.out.println("線程的run方法執行結束");}
}// 測試類
public class Task3InterruptTest {public static void main(String[] args) {Task3 task = new Task3();Thread thread = new Thread(task);thread.start();thread.interrupt(); // 中斷thread線程的執行}
}程序運行結果:
線程的run方法開始執行
線程被中斷
線程運行,i=0
線程運行,i=1
線程運行,i=2
線程的run方法執行結束
以上的程序說明,Thread.interrupted()會清除中斷標記,thread線程沒有了中斷標記,因此Thread.currentThread().isInterrupted()的結果為false,所以線程繼續執行,程序會輸出1-3的數字。
下面我們來看一下如果處于阻塞狀態(調用了sleep、join等方法)的線程,被執行了中斷操作,會有什么樣的結果。
答案很明顯,處于阻塞狀態下的線程被執行了中斷操作,會拋出中斷異常InterruptedException。
示例3:處于阻塞狀態的線程被執行中斷操作的結果演示
public class Task4 implements Runnable {@Overridepublic void run() {System.out.println("線程的run方法開始執行");try {Thread.sleep(5000); // 線程休眠5秒System.out.println("線程完成5秒鐘的休眠");} catch (InterruptedException e) {e.printStackTrace();}System.out.println("線程的run方法執行結束");}
}// 測試類
public class Task4InterruptTest {public static void main(String[] args) {Task4 task = new Task4();Thread thread = new Thread(task);thread.start();try {Thread.sleep(2000); // 主線程休眠2秒} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt(); // 中斷thread線程的執行}
}程序運行結果:
線程的run方法開始執行
java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at testThread.day3.Task4.run(Task4.java:8)at java.lang.Thread.run(Unknown Source)
線程的run方法執行結束
通過上面的程序可以看出,處于阻塞狀態下的線程被執行了中斷操作,會拋出中斷異常InterruptedException,但是thread線程在捕獲到異常后,輸出了“線程的run方法執行結束”的文字,說明thread線程在接收到中斷指令后,并沒有中斷線程的執行,而是繼續向下執行。
通過以上的程序示例,我們可以得出一個結論,那就是線程在執行了中斷指令后,其實是給線程發了一個中斷信號,線程被打上中斷標記,如果線程沒有對中斷標記進行判斷,做相應的處理,那么線程默認會繼續執行,直到線程操作結束。
那么,問題來了,處于阻塞狀態的線程被執行中斷指令后,如何做到線程的中斷呢,請看以下的代碼。
示例4:處于阻塞狀態的線程被執行中斷指令后,立即把線程中斷
public class Task5 implements Runnable {@Overridepublic void run() {System.out.println("線程的run方法開始執行");try {Thread.sleep(5000); // 線程休眠5秒System.out.println("線程完成5秒鐘的休眠");} catch (InterruptedException e) {// 在catch塊里進行處理,再次調用interrupt方法,線程是否會中斷執行呢?System.out.println("線程被中斷");Thread.currentThread().interrupt();}for (int i = 0; i < 3; i++) {System.out.println(i);}System.out.println("線程的run方法執行結束");}
}// 測試類
public class Task5InterruptTest {public static void main(String[] args) {Task5 task = new Task5();Thread thread = new Thread(task);thread.start();try {Thread.sleep(2000); // 主線程休眠2秒} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt(); // 中斷thread線程的執行}
}程序運行結果
線程的run方法開始執行
線程被中斷
0
1
2
線程的run方法執行結束
通過上面的程序,大家會感到奇怪,明明已經在catch塊里,又調用了Thread.currentThread().interrupt()方法,但是線程還是沒有中斷,繼續往下執行。
在這里再一次和大家要強調說明的就是,調用線程的interrupt()方法,不是說線程就不執行了,而是向線程發出了中斷信號,線程被打上中斷標記,如果想讓線程中斷,必須在run方法里對中斷信號進行響應,讓程序return返回到被調用處,才能使線程真正的中斷。
示例5:正確的讓線程中斷的例子
public class Task6 implements Runnable {@Overridepublic void run() {System.out.println("線程的run方法開始執行");try {Thread.sleep(5000); // 線程休眠5秒System.out.println("線程完成5秒鐘的休眠");} catch (InterruptedException e) {// 在catch塊里進行處理,讓程序返回被調用處System.out.println("線程被中斷");return;}for (int i = 0; i < 3; i++) {System.out.println(i);}System.out.println("線程的run方法執行結束");}
}// 測試類
public class Task6InterruptTest {public static void main(String[] args) {Task6 task = new Task6();Thread thread = new Thread(task);thread.start();try {Thread.sleep(2000); // 主線程休眠2秒} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt(); // 中斷thread線程的執行}
}程序運行結果:
線程的run方法開始執行
線程被中斷
通過上面的程序,可以看出,使用return可以做到中斷線程。
線程的中斷其實是為了優雅的停止線程的運行,為了不使用stop方法而設置的。因為JDK不推薦使用stop方法進行線程的停止,因為stop方法會釋放鎖并強制終止線程,會造成執行一半的線程終止,帶來數據的不一致性。