如何正確的中斷執行緒?你的姿勢是否正確
Java停止執行緒的邏輯(協同、通知)
在Java程式中,我們想要停止一個執行緒可以通過interrupt方法進行停止。但是當我們調用interrupt方法之後,它可能並不會立刻就會停止執行緒,而是通知執行緒需要停止。執行緒接收到通知之後會根據自身的情況判斷是否需要停止,它可能會立即停止,也有可能會執行一段時間後停止,也可能根本就不停止。
那麼Java為什麼要選擇這種非強制性的執行緒中斷呢?其實更多是為了數據安全,保證程式的健壯性。因為我們不知道程式正在做什麼事情。如果貿然停止,可能會造成數據的錯亂、不完整。
一個簡單的例子:
public class _24_ThreadTest implements Runnable {
@Override
public void run() {
int count = 0;
while (!Thread.currentThread().isInterrupted() && count <= 2000) {
System.out.println("count: " + count++);
}
}
public static void main(String[] args) throws Exception {
_24_ThreadTest threadTest = new _24_ThreadTest();
Thread thread = new Thread(threadTest);
thread.start();
Thread.sleep(10);
// 中斷執行緒
thread.interrupt();
}
}
這個例子是一個簡單的通過interrupt中斷執行緒的案例,run方法中通過判斷當前執行緒是否中斷,並且count是否大於2000來進行循環。如果執行緒中斷則退出循環,執行緒執行結束。這種就屬於執行緒正常停止的情況。
Sleep是否會收到執行緒中斷訊號
public class _24_ThreadTest implements Runnable {
@Override
public void run() {
int count = 0;
while (!Thread.currentThread().isInterrupted() && count <= 2000) {
try {
System.out.println("count: " + count++);
// 子執行緒睡眠
Thread.sleep(1000 * 2);
System.out.println("方法體:" + Thread.currentThread().isInterrupted());
} catch (InterruptedException e) {
System.out.println("異常:" + Thread.currentThread().isInterrupted());
// 執行緒中斷標誌位被重置為false
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
_24_ThreadTest threadTest = new _24_ThreadTest();
Thread thread = new Thread(threadTest);
thread.start();
Thread.sleep(10);
// 中斷執行緒
thread.interrupt();
}
}
如果在子執行緒中睡眠中,主執行緒通過interrupt方法進行中斷,那麼子執行緒還能不能收到中斷訊號。其實在這種情況下執行緒也是可以接收到訊號通知的,這個時候會拋出InterruptedException,並且將執行緒中斷標誌位設置為false。
在拋出異常後,執行緒標誌位被設置為false,那麼在下次循環判斷count沒有為false的情況下,還是可以進入循環體的。這個時候執行緒就無法停止。
執行結果:
案例場景:
在進行一些後台任務通過執行緒跑的時候,如果在循環中遇到執行緒中斷異常,我們需要終止當前任務,並且告訴客戶端當前任務執行失敗的是哪條記錄,這種情況下就可以通過異常中再次中斷的方式來停止執行緒,並且可以返回給客戶端當前出現異常的記錄是哪條。而不會是接著執行下去。
解決方法
public class _24_ThreadTest implements Runnable {
@Override
public void run() {
int count = 0;
while (!Thread.currentThread().isInterrupted() && count <= 2000) {
try {
System.out.println("count: " + count++);
// 子執行緒睡眠
Thread.sleep(1000 * 2);
Thread.currentThread().interrupt();
System.out.println("方法體:" + Thread.currentThread().isInterrupted());
} catch (InterruptedException e) {
// 再次中斷
Thread.currentThread().interrupt();
System.out.println("異常:" + Thread.currentThread().isInterrupted());
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
_24_ThreadTest threadTest = new _24_ThreadTest();
Thread thread = new Thread(threadTest);
thread.start();
Thread.sleep(10);
// 中斷執行緒
thread.interrupt();
}
}
既然我們已經知道,在出現執行緒中斷異常之後執行緒中斷標誌位會被重置為false,那麼我們可以在異常中手動的再次中斷當前執行緒,那麼就可以完全停止執行緒任務。
總結
上面我們簡單介紹了如何正確的停止執行緒,如果在以後的面試中被問到這類問題,那麼你是不是可以流暢的回答面試官了。
在run方法中遇到異常,我們是不能直接生吞的,一定要做處理,你可以是簡單的日誌記錄,也可以中斷執行緒。但就是不能不做任何處理。
其實還有其他的一些方法來停止執行緒,比如stop(),這類方法已被捨棄,這種強制停止可能會引起執行緒的數據安全問題,所以已經不再推薦使用了。