JAVA併發程式設計(四)任務的取消與關閉
阿新 • • 發佈:2019-01-25
概述
之前三篇文章介紹了多執行緒的同步,加鎖機制,同步容器,併發容器,以及多執行緒工具類,執行緒池等。
大多數時候,我們會讓執行緒執行直到結束。然而,有時候我們希望提前結束任務,或者因為使用者取消了操作,需要終止執行緒。我們來看一下如何使一個執行緒安全、快速、可靠的停下來。
任務取消的原因
1、使用者主動取消。如點選圖形介面的取消按鈕等。
2、有時間限制的操作。當超過時間限制時,需要結束任務。
3、應用程式事件。當一個任務找到解決方案時,需要結束操作。
4、出現錯誤。當任務執行過程中出現不可恢復的錯誤,需要結束任務。
5、關閉。當一個程式被關閉時,需要做一些清理操作。
使用簡單標誌位儲存取消狀態
為了保證標誌位可靠,標誌必須為volatile型別。/**
*
* @author chao
*
*/
public class SafeCancel extends Thread {
private volatile boolean cancelled;
@Override
public void run() {
while (!cancelled) {
// todo something
}
}
public void cancel() {
cancelled = true;
}
}
一個可取消的任務必須擁有取消策略。這個策略需要詳細定義如何取消改任務,何時檢查是否已經取消以及在響應取消請求之後該執行哪些操作。中斷
使用標誌位來取消任務是不及時的,如果中間呼叫了阻塞方法,有可能永遠都無法結束。每個執行緒都有一個boolean型別的中斷狀態,interrupt方法能中斷目標執行緒,而isInterrupted方法能返回目標執行緒的中斷狀態,靜態的interrupted方法將清除當前執行緒的中斷狀態,也是清除中斷狀態的唯一一個方法。/** * * @author chao * */ class InterruptCancel extends Thread { BlockingQueue<Object> queue = new LinkedBlockingQueue<>(); @Override public void run() { try { while (!isInterrupted()) { Object info = new Object(); // do something queue.put(info); } } catch (InterruptedException e) { } } public void cancel() { interrupt(); } }
中斷響應
當呼叫可中斷的阻塞方法時,有兩種策略可用於處理InterruptedException1、傳遞異常,從而使你的方法也成為可中斷的阻塞方法。2、恢復中斷狀態,從而使呼叫棧上中的上層程式碼能夠對其進行處理。只有實現了執行緒中斷策略的程式碼才可以遮蔽中斷請求,常規任務中不應該遮蔽中斷請求。通過Future實現取消
private static ExecutorService service = Executors.newCachedThreadPool();
public static void timedRun(Runnable r, long timeout, TimeUnit unit) {
Future<?> task = service.submit(r);
try {
task.get(timeout, unit);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
} finally {
task.cancel(true);
}
}
關閉ExecutorService
ExecutorService提供了兩種關閉方法:使用shutdown正常關閉,使用shutdownNow強行關閉。在進行強行關閉時,首先關閉當前正在進行的任務,然後返回所有尚未啟動的任務清單。處理未捕獲的異常
Thread API提供了UncaughtExceptionHandler,檢測出某個執行緒由於未捕獲異常而終結的情況。在Android開發中,可以用來上報異常,發現問題及時修復。Thread的方法 public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler paramUncaughtExceptionHandler)
{
SecurityManager localSecurityManager = System.getSecurityManager();
if (localSecurityManager != null) {
localSecurityManager.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));
}
defaultUncaughtExceptionHandler = paramUncaughtExceptionHandler;
}
public static abstract interface UncaughtExceptionHandler
{
public abstract void uncaughtException(Thread paramThread, Throwable paramThrowable);
}
Android中提供了另一個方法,單獨設定每個執行緒的未捕獲異常處理,更加靈活。
public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
uncaughtHandler = handler;
}
JVM關閉鉤子
在線上Java程式中經常遇到程序程掛掉,一些狀態沒有正確的儲存下來,這時候就需要在JVM關掉的時候執行一些清理現場的程式碼。Java中得ShutdownHook提供了比較好的方案。JDK在1.3之後提供了Java Runtime.addShutdownHook(Thread hook)方法,可以註冊一個JVM關閉的鉤子,這個鉤子可以在以下幾種場景被呼叫:
1)程式正常退出
2)使用System.exit()
3)終端使用Ctrl+C觸發的中斷
4)系統關閉
5)使用Kill pid命令幹掉程序
歡迎掃描二維碼,關注公眾號