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)文章
SpringBoot+Redis防止惡意刷新與暴力請求接口的實現(xiàn)
這篇文章主要為大家介紹了如何利用springboot和Redis來實現(xiàn)防止惡意刷新與暴力請求接口,文中的示例代碼講解詳細(xì),需要的可以參考一下2022-06-06
Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解
這篇文章主要為大家介紹了Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
Spring Boot實現(xiàn)通用的接口參數(shù)校驗
本文介紹基于 Spring Boot 和 JDK8 編寫一個 AOP ,結(jié)合自定義注解實現(xiàn)通用的接口參數(shù)校驗。具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05
Java基于FFmpeg實現(xiàn)Mp4視頻轉(zhuǎn)GIF
FFmpeg是一套可以用來記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開源計算機(jī)程序。本文主要介紹了在Java中如何基于FFmpeg進(jìn)行Mp4視頻到Gif動圖的轉(zhuǎn)換,感興趣的小伙伴可以了解一下2022-11-11
Java創(chuàng)建可執(zhí)行JAR文件的多種方式
本文主要介紹了Java創(chuàng)建可執(zhí)行JAR文件的多種方式,使用JDK的jar工具、IDE、Maven和Gradle來創(chuàng)建和配置可執(zhí)行JAR文件,具有一定的參考價值,感興趣的可以了解一下2024-07-07
SpringBoot實現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼
在實際項目開發(fā)過程中,我們經(jīng)常將返回數(shù)據(jù)的基本形式統(tǒng)一為JSON格式的數(shù)據(jù)。但項目可能是由很多人開發(fā)的,所以我們最好將返回的結(jié)果統(tǒng)一起來。本文介紹了SpringBoot實現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼,需要的可以參考一下2022-06-06

