Java面試題:線程池內“鬧情緒”的線程,怎麼辦?

在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接口的異常處理器,當線程出現異常時,異常處理器會被調用,我們可以在其中記錄日誌或者進行其它處理。接着,我們需要將異常處理器設置到線程池的線程工廠中。當線程池內的線程出現異常時,異常處理器就會被調用,我們可以在其中處理異常。

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章