前言
同步组件 CountDownLatch 的使用感觉比较复杂,本章主要讲 CompletableFuture 简单使用,希望有助于替换 CountDownLatch。
1.创建任务
一般简单创建任务使用 supplyAsync、runAsync
supplyAsync
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
runAsync
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
不指定执行的 Executor ,默认使用 ForkJoinPool.commonPool()
例如:
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 不指定,默认使用 ForkJoinPool.commonPool()
CompletableFuture.runAsync(() -> System.out.println("默认使用ForkJoin 1"));
CompletableFuture<String> useForkJoinPool = CompletableFuture.supplyAsync(() -> {
System.out.println("默认使用ForkJoin 2");
return "ForkJoin Result";
});
//
ExecutorService executor = Executors.newFixedThreadPool(2);
// 指定 executor
CompletableFuture<String> executorResult = CompletableFuture.supplyAsync(() -> {
System.out.println("指定executor 1");
return "Executor result";
}, executor);
CompletableFuture.runAsync(() -> System.out.println("指定executor 2"), executor);
//
System.out.println(useForkJoinPool.get());
System.out.println(executorResult.get());
}
// 执行结果
// 默认使用ForkJoin 1
// 默认使用ForkJoin 2
// 指定executor 1
// ForkJoin Result
// 指定executor 2
// Executor result
2.任务简单连续执行或回调
主要说一下带 Async 和不带的区别(指定的执行线程池一致)
例如:
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(4);
CompletableFuture.runAsync(() -> {
System.out.println("执行任务1-thread name = " + Thread.currentThread().getName());
}, executor).thenRunAsync(() -> {
System.out.println("接着执行任务2-thenRunAsync-thread name = " + Thread.currentThread().getName());
}, executor);
CompletableFuture.runAsync(() -> {
System.out.println("执行任务3-thread name = " + Thread.currentThread().getName());
}, executor).thenRun(() -> {
System.out.println("接着执行任务4-thenRun-thread name = " + Thread.currentThread().getName());
});
}
// 输出结果1
// 执行任务1-thread name = pool-1-thread-1
// 接着执行任务2-thenRunAsync-thread name = pool-1-thread-2
// 执行任务3-thread name = pool-1-thread-3
// 接着执行任务4-thenRun-thread name = main
// 输出结果2
// 执行任务1-thread name = pool-1-thread-1
// 接着执行任务2-thenRunAsync-thread name = pool-1-thread-2
// 执行任务3-thread name = pool-1-thread-3
// 接着执行任务4-thenRun-thread name = pool-1-thread-3
就从方法名理解就行,带 Async 就异步,不带就不换线程。
主要说一下出现【mian】线程,CompletableFuture 会尝试使用主线程去执行任务的优化。
3.多任务组合
applyToEitherAsync 示例:
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(6);
CompletableFuture<String> taskOne = CompletableFuture.supplyAsync(() -> {
System.out.println("执行任务1-thread name = " + Thread.currentThread().getName());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "执行任务1 结果";
});
CompletableFuture.supplyAsync(() -> {
System.out.println("执行任务2-thread name = " + Thread.currentThread().getName());
return "执行任务2 结果";
}, executor).applyToEitherAsync(taskOne, (taskOneResult) -> {
System.out.println(taskOneResult);
return "执行任务3 结果";
}, executor);
}
// 输出
// 执行任务1-thread name = ForkJoinPool.commonPool-worker-9
// 执行任务2-thread name = pool-1-thread-1
// 执行任务2 结果
AllOf获取多个任务的结果
如果执行的任务异常,anyOf的CompletableFuture,执行get方法,会抛出异常。
这里需要注意get()、join() 的使用。get可以给定超时时间,这个是很实用的。
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
List<CompletableFuture<String>> completableFutureList = new ArrayList<>();
ExecutorService executor = Executors.newFixedThreadPool(6);
CompletableFuture<String> taskOne = CompletableFuture.supplyAsync(() -> "执行任务1 结果");
CompletableFuture<String> taskThree = CompletableFuture.supplyAsync(() -> {
System.out.println("执行任务2-thread name = " + Thread.currentThread().getName());
return "执行任务2 结果";
}, executor).thenCombineAsync(taskOne, (taskTwoResult, taskOneResult) -> {
System.out.println(taskTwoResult);
return "执行任务3 结果";
}, executor);
completableFutureList.add(taskOne);
completableFutureList.add(taskThree);
CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[]{})).get(400, TimeUnit.MILLISECONDS);
List<String> result = completableFutureList.stream().map(CompletableFuture :: join).collect(Collectors.toList());
System.out.println(result);
// 输出
// 执行任务2-thread name = pool-1-thread-1
// 执行任务2 结果
// [执行任务1 结果, 执行任务3 结果]
}