Java線程里:“中斷”就是指“終止”,與操作系統里的"中斷"、“異常”是完全不同的概念; 由於stop()方法過於暴力,可能導致資源回收無法風險、開銷過大等問題,此方法已過期,故Java中沒有強制中斷線程的手段;但可以調用interupt()、interupted()方法來向進程提出中斷請求,待進 ...
Java線程里:“中斷”就是指“終止”,與操作系統里的"中斷"、“異常”是完全不同的概念;
由於stop()方法過於暴力,可能導致資源回收無法風險、開銷過大等問題,此方法已過期,故Java中沒有強制中斷線程的手段;但可以調用interupt()、interupted()方法來向進程提出中斷請求,待進程自行處理,這是一種更優雅的中斷方式。
註意:當需要中斷線程時,最佳實踐就是利用線程的中斷位,而不是自定義中斷狀態,因為當線程被阻塞時,原生中斷位仍然會被監聽,而自定義的則不能。
以下兩類場景會應用到線程中斷:
-
用來打斷正在阻塞的線程:阻塞在sleep/wait/join等方法上、 阻塞在io-channel讀寫操作上、阻塞在io-channel-selector上。
-
打斷正常執行的線程:需要在目標線程內部檢測中斷位,並由用戶手動終止,來做出響應。
-
interrupt()
實例方法,線上程內外都可發起調用;其作用是中斷此線程(此線程不一定是當前線程,而是指調用該方法的Thread實例所代表的線程),但實際上只是給線程設置一個中斷標誌,線程仍會繼續運行。)作用與正常線程會將中斷標記設置為true,但是作用於阻塞線程會將中斷標誌刷新false(中斷標記預設為false,刷新就是重新刷會預設)。 -
interrupted()
靜態方法,只能線上程內部調用;作用是測試當前線程是否被中斷(檢查中斷標誌),返回一個boolean並清除中斷狀態,第二次再調用時中斷狀態已經被清除,將返回一個false。
-
-
isInterrupted()
作用是只檢測此線程是否被中斷 ,不清除中斷狀態。
- 不線上程內部檢測中斷位並手動響應中斷,線程將無限執行下去:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
System.err.println("子線程");
}
});
thread.start();
System.out.println("---" + thread.isInterrupted()); // ---false
/**
* 這主線程只是改變了子線程的中斷位改為了true
* 由於子線內部並沒有就中斷位進行檢測和處理,故子線程並不會終止,會無限列印下去
*/
thread.interrupt();
TimeUnit.SECONDS.sleep(1);
System.err.println("===" + thread.isInterrupted()); // ===true
}
- 在非阻塞線程內部手動響應中斷:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().isInterrupted());
System.err.println("子線程");
}
});
thread.start();
System.out.println("---" + thread.isInterrupted()); // ---false
/**
* 這主線程只是改變了子線程的中斷位改為了true
*/
TimeUnit.SECONDS.sleep(3);
thread.interrupt();
System.err.println("===" + thread.isInterrupted()); // ===true
}
- 在非阻塞線程內部手動響應中斷:
/**
* 當子線程需要響應主線程的中斷請求,而停止時。可以通過在子線程中實時檢測其自身的中斷狀態來達到停止的目的
*
* @param args
*/
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
// 實時檢測自身中斷狀態
while (!Thread.currentThread().isInterrupted()) {
System.err.println("子線程");
}
});
thread.start();
TimeUnit.SECONDS.sleep(2);
// 修改子線程的中斷狀態
thread.interrupt();
}
- 中斷阻塞中的線程:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// 異常被捕獲後,阻塞被打破、中斷位被設為false,所以異常中永遠輸出false
System.out.println("2 ----" + Thread.currentThread().isInterrupted()); // 2 ----false
System.err.println("回收資源");
e.printStackTrace();
}
System.err.println("子線程邏輯");
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
System.out.println(thread.isInterrupted()); // true
TimeUnit.SECONDS.sleep(5);
}
- 優雅中斷非阻塞線程:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (true) {
if (Thread.interrupted()) {
System.out.println("清理資源");
break;
}
System.err.println("子線程邏輯");
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
}
學習使我充實,分享給我快樂!