Java沒有提供任何機制來安全地(搶佔式方法)終止線程,雖然Thread.stop和suspend等方法提供了這樣的機制,但是由於存在着一些嚴重的缺陷,因此應該避免使用。但它提供了中斷Interruption機制,這是一種協作機制,能夠使一個線程終止另一個線程的當前工作。
一、任務取消
取消操作的原因:
. 用戶請求取消
. 有時間限制的操作
. 應用程序事件
. 錯誤
. 關閉
結束任務的四種方式:
1. run方法執行結束
2. 使用請求關閉標記(例如boolean開關)
3. 使用中斷機制
4. 使用Future退出方法
2. 使用請求關閉標記
當執行到並滿足條件是使用return退出run方法
變量需要volatile確保變量多線程環境下的可見性。
-例子待填充,沒有執行到判斷條件就不會退出,所以不是立即退出的辦法。
3. 使用中斷機制
優點是相對“請求關閉標記”相應更快一些,但也不是立即關閉線程。
void interrupt() 中斷線程。
boolean interrupted() 測試當前線程是否已經中斷。
boolean isInterrupted() 測試線程是否已經中斷。
InterruptedException異常
程序應該對線程中斷作出恰當的響應。// 1
Thread thread = new Thread("interrupt test") {
public void run() {
for (;;) {
doXXX();
if (Thread.interrupted()) {
break;
}
}
}
};
thread.start();
// 2
Thread thread = new Thread("interrupt test") {
public void run() {
for (;;) {
try {
doXXX();
} catch (InterruptedException e) {
break;
} catch (Exception e) {
// handle Exception
}
}
}
};
thread.start();
// 3
public void foo() throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
4. 使用Future退出方法
boolean cancel(boolean mayInterruptIfRunning)
試圖取消對此任務的執行。
boolean isCancelled()
如果在任務正常完成前將其取消,則返回 true。
*. 處理不可中斷的阻塞
*. 採用newTaskFor來封裝費標準的取消
二、停止基於線程的服務
之前的任務取消,主要是涉及如何關閉單個線程並且都是由創建單個線程的對象來進行關閉操作,但是如果線程不是由對象自己而是由線程池統一創建的線程該如何處理呢?
1. 使用線程的對象進行關閉 - 當前即使不在對象中創建線程而由線程池創建,這個對象依然可以關閉線程,這點一定要相信程序員的破壞能力,只是使用第2種方式更符合封裝原則。
2. 使用線程池統一管理 - 如果是使用ExecutorService創建就交由其進行關閉操作。
2. 使用線程池統一管理(關閉ExecutorService)
void shutdown()
啓動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則調用沒有其他作用。
-- 安全關閉方式。
List<Runnable> shutdownNow()
試圖停止所有正在執行的活動任務,暫停處理正在等待的任務,並返回等待執行的任務列表。
無法保證能夠停止正在處理的活動執行任務,但是會盡力嘗試。例如,通過 Thread.interrupt() 來取消典型的實現,所以任何任務無法響應中斷都可能永遠無法終止。
-- shutdownNow方法的侷限性,強制關閉方式。
boolean isShutdown()
boolean isShutdown()如果此執行程序已關閉,則返回 true。
3. “毒丸”對象
只有在生產者消費者的數量都已知的情況下,纔可以使用“毒丸”對象。
三、處理非正常的線程終止
Thread.UncaughtExceptionHandler全局的捕獲的異常處理,通常在應用中用於異常的統計,收集到這些統計後可以對應用進行異常修復。
四、JVM關閉
1. 關閉鉤子
Runtime.getRuntime().addShutdownHook(new Thread()) ;
void addShutdownHook(Thread hook)
註冊新的虛擬機來關閉鉤子。
2. 守護線程
希望創建一個線程來執行一些輔助工作,但又不希望這個線程阻礙JVM的關閉,可以使用守護線程。
3. 終結器
避免使用終結器finalize
五、參考資料:
"程序應該對線程中斷作出恰當的響應" 摘錄自《溫紹錦 - Java併發程序設計教程》