Executors 和 CompletableFuture 是Java中用于并发编程的两个不同工具,它们在用途、实现和使用方式上有显著的区别。
Executors
Executors 是一个工具类,用于创建和管理线程池。它提供了一些静态方法来创建不同类型的线程池,例如固定大小的线程池、缓存线程池、单线程池和定时线程池。
主要特点和用法
-
线程池管理:
Executors.newFixedThreadPool(int nThreads):创建固定大小的线程池。Executors.newCachedThreadPool():创建一个按需创建线程的线程池。Executors.newSingleThreadExecutor():创建一个只有一个线程的线程池。Executors.newScheduledThreadPool(int corePoolSize):创建一个可以调度的线程池。
-
任务提交:
- 使用
ExecutorService的submit()方法提交任务,任务可以是Runnable或Callable。 - 线程池负责管理线程的生命周期,任务执行完后可以复用线程。
- 使用
-
示例:
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.submit(() -> {
System.out.println("Task is running in thread pool");
});
executorService.shutdown();
CompletableFuture
CompletableFuture 是Java 8引入的一个类,用于处理异步编程。它允许你以非阻塞的方式编写异步代码,并提供了一套丰富的API进行任务的组合、回调和错误处理。
主要特点和用法
-
异步任务:
- 使用
CompletableFuture.supplyAsync(Supplier<U> supplier)或CompletableFuture.runAsync(Runnable runnable)提交异步任务。 - 提供
thenApply(),thenAccept(),thenCompose()等方法进行任务的组合和回调。
- 使用
-
非阻塞:
- 通过回调方法处理异步任务的结果,避免阻塞主线程。
- 可以处理异常,例如使用
exceptionally()方法。
-
示例:
CompletableFuture.supplyAsync(() -> {
// 异步任务
return "Hello";
}).thenApply(result -> {
// 转换结果
return result + " World";
}).thenAccept(result -> {
// 消费结果
System.out.println(result);
}).exceptionally(ex -> {
// 处理异常
System.err.println("Exception: " + ex.getMessage());
return null;
});
区别总结
-
用途:
Executors主要用于管理线程池和并发任务的执行,适用于需要显式控制线程池和线程生命周期的场景。CompletableFuture主要用于处理异步编程,适用于需要进行复杂的异步任务组合、回调和非阻塞处理的场景。
-
编程风格:
Executors采用传统的线程池管理方式,任务提交后可以使用Future获取结果。CompletableFuture采用函数式编程风格,通过链式调用进行任务的组合和回调处理。
-
非阻塞处理:
- 使用
Executors提交的任务可以通过Future.get()获取结果,但这是一个阻塞操作。 CompletableFuture提供了非阻塞的回调方法,例如thenApply(),thenAccept(),可以在任务完成时进行处理而无需阻塞当前线程。
- 使用
-
错误处理:
Executors中的任务错误处理需要显式捕获异常。CompletableFuture提供了专门的方法进行错误处理,例如exceptionally()和handle()。
示例对比
以下是一个示例,展示了如何使用 Executors 和 CompletableFuture 分别实现异步任务:
import java.util.concurrent.*;
public class ExecutorsVsCompletableFuture {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 使用 Executors 管理线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
Future<String> future = executorService.submit(() -> {
Thread.sleep(1000);
return "Result from Executors";
});
System.out.println("Task submitted with Executors");
// 使用 CompletableFuture 处理异步任务
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Result from CompletableFuture";
});
completableFuture.thenAccept(result -> System.out.println(result));
// 获取 Executors 的任务结果(这将阻塞当前线程)
System.out.println(future.get());
// 关闭线程池
executorService.shutdown();
}
}
在这个示例中,Executors 的任务结果通过 Future.get() 获取,这会阻塞当前线程。而 CompletableFuture 通过 thenAccept() 进行回调处理,不会阻塞主线程。