Java捕獲ThreadPoolExecutor內(nèi)部線程異常的四種方法
方案 1
使用 execute
+ try-catch
記錄異常
import java.util.concurrent.*; public class ThreadPoolExceptionDemo { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 4, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadFactory() { private int count = 1; @Override public Thread newThread(Runnable r) { return new Thread(r, "custom-thread-" + count++); } }); executor.execute(() -> { try { System.out.println(Thread.currentThread().getName() + " 正在執(zhí)行任務(wù)"); throw new RuntimeException("任務(wù)異常"); } catch (Exception e) { System.err.println("線程 " + Thread.currentThread().getName() + " 捕獲異常: " + e.getMessage()); e.printStackTrace(); } }); executor.shutdown(); } }
方案 2
使用 submit + Future
submit()
方法返回 Future
,可以通過 get()
方法捕獲異常:
public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); Future<?> future = executor.submit(() -> { System.out.println(Thread.currentThread().getName() + " 正在執(zhí)行任務(wù)"); throw new RuntimeException("任務(wù)異常"); }); try { future.get(); // get() 會拋出 ExecutionException } catch (InterruptedException | ExecutionException e) { System.err.println("線程 " + Thread.currentThread().getName() + " 捕獲異常: " + e.getCause().getMessage()); e.printStackTrace(); } executor.shutdown(); }
注意
- get() 方法會阻塞主線程直到任務(wù)完成。
- ExecutionException 的 getCause() 方法可以獲取原始異常。
方案 3
自定義 UncaughtExceptionHandler
可以為線程設(shè)置 UncaughtExceptionHandler,當(dāng) Runnable 沒有捕獲異常時,ThreadPoolExecutor 也不會吞掉異常:
public class ThreadPoolWithExceptionHandler { public static void main(String[] args) { ThreadFactory threadFactory = r -> { Thread t = new Thread(r); t.setUncaughtExceptionHandler((thread, throwable) -> { System.err.println("線程 " + thread.getName() + " 發(fā)生異常: " + throwable.getMessage()); throwable.printStackTrace(); }); return t; }; ExecutorService executor = new ThreadPoolExecutor( 2, 4, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), threadFactory ); executor.execute(() -> { System.out.println(Thread.currentThread().getName() + " 正在執(zhí)行任務(wù)"); throw new RuntimeException("任務(wù)異常"); }); executor.shutdown(); } }
方案 4
重寫 afterExecute 方法
如果你要在 ThreadPoolExecutor
內(nèi)部直接處理異常,可以繼承 ThreadPoolExecutor
并重寫 afterExecute()
:
class CustomThreadPoolExecutor extends ThreadPoolExecutor { public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (t == null && r instanceof Future<?>) { try { ((Future<?>) r).get(); // 獲取任務(wù)結(jié)果,捕獲異常 } catch (InterruptedException | ExecutionException e) { t = e.getCause(); } } if (t != null) { System.err.println("線程 " + Thread.currentThread().getName() + " 發(fā)生異常: " + t.getMessage()); t.printStackTrace(); } } } public class ThreadPoolAfterExecuteDemo { public static void main(String[] args) { ThreadPoolExecutor executor = new CustomThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); executor.submit(() -> { System.out.println(Thread.currentThread().getName() + " 正在執(zhí)行任務(wù)"); throw new RuntimeException("任務(wù)異常"); }); executor.shutdown(); } }
結(jié)論
方案 | 適用場景 | 缺點 |
---|---|---|
try-catch 手動處理 | 適用于 execute() | 代碼侵入性強(qiáng),所有任務(wù)都要加 try-catch |
Future.get() 捕獲異常 | 適用于 submit() | get() 會阻塞主線程 |
UncaughtExceptionHandler | 適用于 execute() | 不能捕獲 submit() 提交的異常 |
afterExecute() | 適用于 execute() 和 submit() | 需要繼承 ThreadPoolExecutor |
推薦:
- 任務(wù)內(nèi)部
try-catch
適用于execute()
Future.get()
適用于submit()
- 統(tǒng)一異常處理建議使用
afterExecute()
或UncaughtExceptionHandler
到此這篇關(guān)于Java捕獲ThreadPoolExecutor內(nèi)部線程異常的四種方法的文章就介紹到這了,更多相關(guān)Java ThreadPoolExecutor異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用openssl檢測網(wǎng)站是否支持ocsp
OCSP在線證書狀態(tài)協(xié)議是為了替換CRL而提出來的。對于現(xiàn)代web服務(wù)器來說一般都是支持OCSP的,OCSP也是現(xiàn)代web服務(wù)器的標(biāo)配,這篇文章主要介紹了Java使用openssl檢測網(wǎng)站是否支持ocsp,需要的朋友可以參考下2022-07-07macOS上使用gperftools定位Java內(nèi)存泄漏問題及解決方案
這篇文章主要介紹了macOS上使用gperftools定位Java內(nèi)存泄漏問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07