為什么廢棄Thread的stop函數?
簡單來說就是stop方法中斷線程太過暴力隨意,且會是否線程持有的鎖,會導致線程安全問題。還有可能導致存在需要被釋放的資源得不到釋放,引發內存泄露。所以用stop停止線程是不推薦的。
- stop是通過立即拋出ThreadDeath異常,來達到停止線程的目的,此異常拋出有可能發生在任何一時間點,包括在catch、finally等語句塊中,但是此異常並不會引起程序退出。
- 由於有異常拋出,導致線程會釋放全部所持有的鎖,極可能引起線程安全問題。
- 有可能導致存在需要被釋放的資源得不到釋放,引發內存泄露。
使用Thread的interrupt()方法結束線程
調用Thread對象的interrupt函數並不是立即中斷線程,只是將線程中斷狀態標志設置為true,當線程運行中有調用其阻塞的函數(Thread.sleep,Object.wait,Thread.join等時,像Thread.sleep()
方法調用之后,會不斷地輪詢檢測中斷狀態標志是否為true,如果為true,則停止阻塞並拋出InterruptedException異常,同時還會重置中斷狀態標志false;如果為false,我們在catch方法體里沒有重新interrupt()把在中斷狀態標志設置為true的話,就會導致循環體無需循環下去,可參考下面的代碼。
注意事項:
- 使用isInterrupted來判斷線程是否處於中斷狀態,若是中斷狀態,則跳出正在執行的任務,使線程結束運行。
- 調用
sleep()
方法觸發InterruptedException
異常時,在catch代碼塊中需再次調用interrupt()
方法,使線程再次處於中斷狀態,使while循環條件為false,使線程跳出循環,結束運行。若不調用,while循環為死循環,線程無法結束。
代碼示例
public class InterruptTest {
/**
* 結束未使用阻塞函數的線程
* @throws InterruptedException
*/
@Test
public void test1() throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("開始搬磚!");
//只要代碼里沒有異常,那么我們可以通過判斷線程是否中斷來執行業務操作
//當其他線程發出線程中斷信號后就會跳出正在執行的任務,往下執行使線程結束運行。
while (!Thread.currentThread().isInterrupted()) {
System.out.println("西西弗斯的陷阱:無腦循環,日復一日搬磚!");
}
System.out.println("神跡出現,結束搬磚!");
System.out.println(Thread.currentThread().isInterrupted());//true
});
thread.start();
TimeUnit.MILLISECONDS.sleep(10);
System.out.println("啟動超級進化形態!");
thread.interrupt();
}
/**
* 開始搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 。。。。。
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 啟動超級進化形態!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 神跡出現,結束搬磚!
*/
/**
* 結束使用阻塞函數的線程
* @throws InterruptedException
*/
@Test
public void test2() throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("開始搬磚!");
//只要代碼里沒有異常,那么我們可以通過判斷線程是否中斷來執行業務操作
//當其他線程發出線程中斷信號后就會跳出正在執行的任務,往下執行使線程結束運行。
while (!Thread.currentThread().isInterrupted()) {
System.out.println("西西弗斯的陷阱:無腦循環,日復一日搬磚!");
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().isInterrupted());//false
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().isInterrupted());//true
}
}
System.out.println("神跡出現,結束搬磚!");
});
thread.start();
TimeUnit.MILLISECONDS.sleep(1000);
System.out.println("啟動超級進化形態!");
thread.interrupt();
//主線程加上這個睡眠時間是為了便於查看當沒有在catch代碼塊中需調用interrupt函數,使線程再次處於中斷狀態,
// 使while循環條件為false,使線程跳出循環,結束運行。若不調用,while循環為死循環,線程無法結束。
TimeUnit.SECONDS.sleep(3000);
}
/**
* catch中有調用 Thread.currentThread().interrupt();
* 開始搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 啟動超級進化形態!
* java.lang.InterruptedException: sleep interrupted
* at java.lang.Thread.sleep(Native Method)
* at java.lang.Thread.sleep(Thread.java:340)
* at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
* at cn.vv.schedule.module.rewardpunishment.service.InterruptTest.lambda$test2$1(InterruptTest.java:64)
* at java.lang.Thread.run(Thread.java:748)
* 神跡出現,結束搬磚!
*/
/**
* catch中沒有調用 Thread.currentThread().interrupt();線程會無需循環下去,直到主線程結束
*開始搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 啟動超級進化形態!
* java.lang.InterruptedException: sleep interrupted
* at java.lang.Thread.sleep(Native Method)
* at java.lang.Thread.sleep(Thread.java:340)
* at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
* at cn.vv.schedule.module.rewardpunishment.service.InterruptTest.lambda$test2$1(InterruptTest.java:64)
* at java.lang.Thread.run(Thread.java:748)
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 西西弗斯的陷阱:無腦循環,日復一日搬磚!
* 。。。。。。一直下去
*/
}
Thread的靜態函數interrupted與Thread的對象函數isInterrupted比較
靜態方法Thread.interrupted()
會在檢測線程中斷狀態標志是否為true后,還會將中斷狀態標志重置為false。
對象方法thread.isInterrupted()
只是檢測線程中斷狀態標志。
//靜態方法
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
//對象方法
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
//ClearInterrupted表示是否清除中斷標示狀態,清除后為false
private native boolean isInterrupted(boolean ClearInterrupted);