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() 會(huì)拋出 ExecutionException } catch (InterruptedException | ExecutionException e) { System.err.println("線程 " + Thread.currentThread().getName() + " 捕獲異常: " + e.getCause().getMessage()); e.printStackTrace(); } executor.shutdown(); }
注意
- get() 方法會(huì)阻塞主線程直到任務(wù)完成。
- ExecutionException 的 getCause() 方法可以獲取原始異常。
方案 3
自定義 UncaughtExceptionHandler
可以為線程設(shè)置 UncaughtExceptionHandler,當(dāng) Runnable 沒有捕獲異常時(shí),ThreadPoolExecutor 也不會(huì)吞掉異常:
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é)論
方案 | 適用場(chǎng)景 | 缺點(diǎn) |
---|---|---|
try-catch 手動(dòng)處理 | 適用于 execute() | 代碼侵入性強(qiáng),所有任務(wù)都要加 try-catch |
Future.get() 捕獲異常 | 適用于 submit() | get() 會(huì)阻塞主線程 |
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用openssl檢測(cè)網(wǎng)站是否支持ocsp
OCSP在線證書狀態(tài)協(xié)議是為了替換CRL而提出來的。對(duì)于現(xiàn)代web服務(wù)器來說一般都是支持OCSP的,OCSP也是現(xiàn)代web服務(wù)器的標(biāo)配,這篇文章主要介紹了Java使用openssl檢測(cè)網(wǎng)站是否支持ocsp,需要的朋友可以參考下2022-07-07java實(shí)現(xiàn)多文件上傳至本地服務(wù)器功能
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)多文件上傳至本地服務(wù)器功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01@SpringBootTest 注解報(bào)紅問題及解決
這篇文章主要介紹了@SpringBootTest 注解報(bào)紅問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11macOS上使用gperftools定位Java內(nèi)存泄漏問題及解決方案
這篇文章主要介紹了macOS上使用gperftools定位Java內(nèi)存泄漏問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07springboot+redis緩存的實(shí)現(xiàn)方案
本文介紹了Spring Boot與Redis結(jié)合實(shí)現(xiàn)緩存的三種方案:注解方式、注解切面類方式和使用樣例,通過這些方案,可以有效地提高應(yīng)用程序的性能和響應(yīng)速度2025-03-03spring?boot集成redisson的最佳實(shí)踐示例
這篇文章主要為大家介紹了spring?boot集成redisson的最佳實(shí)踐示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03