import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class CompletableFutureExample {
// 自定义线程池
private static final ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
2,
4,
10L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10));
public static void main(String[] args) {
// 异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟可能抛出异常的任务
if (Math.random() < 0.5) {
throw new RuntimeException("任务执行出错");
}
return "任务成功执行";
}, customExecutor);
// 处理异常并返回异常信息
future.exceptionally(ex -> {
System.out.println("捕获到异常: " + ex.getMessage());
return "异常信息: " + ex.getMessage();
}).thenAccept(System.out::println);
// 避免因线程池关闭导致任务无法执行
AtomicBoolean isShutdown = new AtomicBoolean(false);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (!isShutdown.getAndSet(true)) {
customExecutor.shutdown();
try {
if (!customExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
customExecutor.shutdownNow();
if (!customExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("Pool did not terminate");
}
}
} catch (InterruptedException ie) {
customExecutor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}));
}
}
关键步骤说明
- 创建自定义线程池:使用
ThreadPoolExecutor
创建了一个自定义线程池customExecutor
,设置了核心线程数、最大线程数、线程存活时间以及任务队列。
- 执行异步任务:通过
CompletableFuture.supplyAsync
方法,将异步任务提交到自定义线程池customExecutor
中执行。任务中模拟了可能抛出异常的情况。
- 异常处理:使用
exceptionally
方法捕获异步任务执行过程中抛出的异常,并返回包含异常信息的字符串。
- 避免线程池关闭问题:通过
Runtime.getRuntime().addShutdownHook
添加一个钩子函数,在程序关闭时,优雅地关闭线程池。先调用shutdown
方法,尝试平稳关闭线程池,如果等待一段时间后仍未关闭,则调用shutdownNow
方法强制关闭,并再次等待一段时间确保线程池完全关闭。同时使用AtomicBoolean
来防止多次关闭线程池。