面试题答案
一键面试面临的挑战
- 线程创建开销:如果频繁创建和销毁
CompletableFuture
对应的线程,会产生较大的线程创建和销毁开销,影响系统性能。 - 线程饥饿:在高并发场景下,可能会出现某些任务长时间得不到执行,因为线程资源被其他任务占用,导致线程饥饿问题。
- 资源耗尽:无限制地创建线程可能会耗尽系统资源,如内存,导致系统崩溃。
优化策略
- 自定义线程池:使用
Executors
创建自定义线程池,通过合理设置线程池参数,如核心线程数、最大线程数、队列容量等,来控制线程资源的使用。 - 复用线程:将
CompletableFuture
的任务提交到线程池中,避免频繁创建新线程,提高线程的复用率。
代码示例
import java.util.concurrent.*;
public class CompletableFutureExample {
// 创建自定义线程池
private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
// 异步任务1
CompletableFuture.supplyAsync(() -> {
System.out.println("Task 1 is running on thread: " + Thread.currentThread().getName());
return "Result of Task 1";
}, executorService)
// 依赖任务1的结果执行任务2
.thenApplyAsync(result1 -> {
System.out.println("Task 2 is running on thread: " + Thread.currentThread().getName());
return result1 + " and Task 2";
}, executorService)
.thenAcceptAsync(finalResult -> {
System.out.println("Final result: " + finalResult);
System.out.println("Task 3 is running on thread: " + Thread.currentThread().getName());
}, executorService);
// 关闭线程池
executorService.shutdown();
}
}
在上述代码中,通过 Executors.newFixedThreadPool(10)
创建了一个固定大小为10的线程池。CompletableFuture.supplyAsync
、thenApplyAsync
和 thenAcceptAsync
方法都将任务提交到这个自定义线程池中执行,避免了频繁创建新线程,有效优化了线程资源的使用。在程序结束时,调用 executorService.shutdown()
关闭线程池。