在Java中,執行緒池中工作執行緒出現異常的時候,預設會把異常往外拋,同時這個工作執行緒會因為異常而銷燬,我們需要自己去處理對應的異常,異常處理的方法有幾種:
-
在傳遞的任務中去處理異常,對於每個提交到執行緒池中的執行的任務,可以提前透過異常進行捕獲,這樣即便出現了異常,也不會影響執行緒池中的工作執行緒
-
使用Future來捕獲異常結果,線上程池中提供了一個submit(Callable<T>)方法,這個方法會返回一個Future,可以透過呼叫Future.get()方法,來獲取任務的執行結果,如果任務執行過程中出現了異常,也會丟擲一個ExecutionException,其中就包含了任務執行過程中出現的異常
-
我們還可以自定義一個ThreadFactory,設定一個UncaughtExceptionHandler,我們可以透過實現ThreadFactory的介面來自定義建立執行緒的方式,然後為每個新建立的執行緒設定一個UncaughtExceptionHandler,這個處理器會線上程由於未捕獲異常而即將終止的時候被呼叫
下面是三段程式碼示例:
捕獲執行緒執行異常
ExecutorService executorService = Executors.newFixedThreadPool(5); executorService.execute(() -> { try { // 執行任務 } catch (Exception e) { // 記錄日誌 logger.error("An exception occurred: ", e); } });
在執行任務的過程中,如果出現異常,就會被try-catch語句捕獲,並將異常資訊記錄到日誌中。
使用Future來捕獲異常結果
ExecutorService executorService = Executors.newFixedThreadPool(5); List<Future<?>> futures = new ArrayList<>(); // 提交任務到執行緒池 for (int i = 0; i < 10; i++) { Future<?> future = executorService.submit(() -> { // 執行任務 }); futures.add(future); } // 獲取任務結果 for (Future<?> future : futures) { try { future.get(); } catch (InterruptedException | ExecutionException e) { // 處理異常 logger.error("An exception occurred: ", e); } }
在這個例子中,我們將多個任務提交到執行緒池,並將每個任務的Future物件儲存在futures列表中。接著,我們遍歷futures列表,並呼叫每個Future物件的get()方法來獲取任務的執行結果。如果任務執行過程中出現了異常,則會丟擲ExecutionException異常,我們在catch塊中捕獲該異常並進行相應的處理。
實現UncaughtExceptionHandler介面
public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { // 記錄日誌或者進行其它處理 logger.error("Thread " + t.getName() + " encountered an exception: ", e); } } ExecutorService executorService = Executors.newFixedThreadPool(5); // 設定UncaughtExceptionHandler ((ThreadPoolExecutor) executorService).setThreadFactory(r -> { Thread thread = new Thread(r); thread.setUncaughtExceptionHandler(new CustomExceptionHandler()); return thread; }); executorService.execute(() -> { // 執行任務 });
這種方式需要自定義一個實現了UncaughtExceptionHandler介面的異常處理器,當執行緒出現異常時,異常處理器會被呼叫,我們可以在其中記錄日誌或者進行其它處理。接著,我們需要將異常處理器設定到執行緒池的執行緒工廠中。當執行緒池內的執行緒出現異常時,異常處理器就會被呼叫,我們可以在其中處理異常。
往期面試題:
Java面試題:@PostConstruct、init-method和afterPropertiesSet執行順序?
Java面試題:SimpleDateFormat是執行緒安全的嗎?使用時應該注意什麼?
Java面試題:細數ThreadLocal大坑,記憶體洩露本可避免
Java面試題:請談談對ThreadLocal的理解?
Java面試題:為什麼HashMap不建議使用物件作為Key?
Java面試題:你知道Spring的IOC嗎?那麼,它為什麼這麼重要呢?
Java面試題:Spring Bean執行緒安全?別擔心,只要你不寫併發程式碼就好了!