常用的四种CompletableFuture创建方式
CompletableFuture中有四个静态方式用来执行异步任务
public static<U> CompletableFuture<U> supplyAsync(Supplier<U> supplier){..}
public static<U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor exeutor){..}
public static CompletableFuture<void> runAsync(Supplier<U> supplier){..}
public static CompletableFuture<void> runAsync(Supplier<U> supplier,Executor exeutor){..}
一般我们用上面的静态方法来创建,
【supplyAsync】 执行任务,支持返回值。
【runAsync】 执行任务,没有返回值。
【supplyAsync方法】
- 使用默认内置的线程池ForkJoinPool.commonPool()
public static<U> CompletableFuture<U> supplyAsync(Supplier<U> supplier){..}
- 使用自定义的线程池
public static<U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor exeutor){..}
【runAsync方法】
- 使用默认内置的线程池ForkJoinPool.commonPool()
public static<U> CompletableFuture<U> supplyAsync(Supplier<U> supplier){..}
- 使用自定义的线程池
public static<U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor exeutor){..}
获取结果的四种方式
// 阻塞获取结果
public T get()
// 在一定时间内阻塞获取结果
public T get(long timeout,TimeUnit unit)
// 立即获取结果不阻塞,结果计算完成返回结果,结果出现异常或未完成计算,返回设定值
public T getNow(T valueIfAbsent)
// 阻塞获取结果,如果计算中出现异常,不抛出异常
public T join()
异步回调方法
1. thenRun/thenRunAsync
@Test
public void testCompletableThenRunAsync() throws InterruptedException, ExecutionException {
long startTime = System.currentTimeMillis();
CompletableFuture<Void> cp1 = CompletableFuture.runAsync(() -> {
try {
//执行任务A
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Void> cp2 = cp1.thenRun(() -> {
try {
//执行任务B
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// get方法测试
System.out.println(cp2.get());
//模拟主程序耗时时间
Thread.sleep(600);
System.out.println("总共用时" + (System.currentTimeMillis() - startTime) + "ms");
}
【thenRun 和thenRunAsync有什么区别】
如果你执行第一个任务的时候,传入了一个自定义线程池:
调用thenRun方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池。
调用thenRunAsync执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoin线程池。
2、thenAccept/thenAcceptAsync
第一个任务执行完成后,执行第二个回调方法任务,会将该任务的执行结果,作为入参,传递到回调方法中,但是回调方法是没有返回值的。
@Test
public void testCompletableThenAccept() throws ExecutionException, InterruptedException {
long startTime = System.currentTimeMillis();
CompletableFuture<String> cp1 = CompletableFuture.supplyAsync(() -> {
return "dev";
});
CompletableFuture<Void> cp2 = cp1.thenAccept((a) -> {
System.out.println("上一个任务的返回结果为: " + a);
});
cp2.get();
}
3、 thenApply/thenApplyAsync
表示第一个任务执行完成后,执行第二个回调方法任务,会将该任务的执行结果,作为入参,传递到回调方法中,并且回调方法是有返回值的。
@Test
public void testCompletableThenApply() throws ExecutionException, InterruptedException {
CompletableFuture<String> cp1 = CompletableFuture.supplyAsync(() -> {
return "dev";
}).thenApply((a) -> {
if(Objects.equals(a,"dev")){
return "dev";
}
return "prod";
});
System.out.println("当前环境为:" + cp1.get());
}
多任务组合回调
1、AND组合关系
thenCombine / thenAcceptBoth / runAfterBoth都表示:
「当任务一和任务二都完成再执行任务三」。
区别在于:
【runAfterBoth】 不会把执行结果当做方法入参,且没有返回值
【thenAcceptBoth】: 会将两个任务的执行结果作为方法入参,传递到指定方法中,且无返回值
【thenCombine】:会将两个任务的执行结果作为方法入参,传递到指定方法中,且有返回值
@Test
public void testCompletableThenCombine() throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务1结束");
return result;
}, executorService);
//开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务2,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务2结束");
return result;
}, executorService);
//任务组合
CompletableFuture<Integer> task3 = task.thenCombineAsync(task2, (f1, f2) -> {
System.out.println("执行任务3,当前线程是:" + Thread.currentThread().getId());
System.out.println("任务1返回值:" + f1);
System.out.println("任务2返回值:" + f2);
return f1 + f2;
}, executorService);
Integer res = task3.get();
System.out.println("最终结果:" + res);
}
2、OR组合关系
applyToEither / acceptEither / runAfterEither 都表示:「两个任务,只要有一个任务完成,就执行任务三」。
区别在于:
【runAfterEither】:不会把执行结果当做方法入参,且没有返回值
【acceptEither】: 会将已经执行完成的任务,作为方法入参,传递到指定方法中,且无返回值
【applyToEither】:会将已经执行完成的任务,作为方法入参,传递到指定方法中,且有返回值
public void testCompletableEitherAsync() {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务1结束");
return result;
}, executorService);
//开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务2,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 2;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务2结束");
return result;
}, executorService);
//任务组合
task.acceptEitherAsync(task2, (res) -> {
System.out.println("执行任务3,当前线程是:" + Thread.currentThread().getId());
System.out.println("上一个任务的结果为:"+res);
}, executorService);
}
3、多任务组合
【allOf】:等待所有任务完成
@Test
public void testCompletableAallOf() throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务1,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 1;
System.out.println("异步任务1结束");
return result;
}, executorService);
//开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务2,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 2;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务2结束");
return result;
}, executorService);
//开启异步任务3
CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务3,当前线程是:" + Thread.currentThread().getId());
int result = 1 + 3;
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务3结束");
return result;
}, executorService);
//任务组合
CompletableFuture<Void> allOf = CompletableFuture.allOf(task, task2, task3);
//等待所有任务完成
allOf.get();
//获取任务的返回结果
System.out.println("task结果为:" + task.get());
System.out.println("task2结果为:" + task2.get());
System.out.println("task3结果为:" + task3.get());
}
【anyOf】:只要有一个任务完成
@Test
public void testCompletableAnyOf() throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//开启异步任务1
CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
int result = 1 + 1;
return result;
}, executorService);
//开启异步任务2
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
int result = 1 + 2;
return result;
}, executorService);
//开启异步任务3
CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
int result = 1 + 3;
return result;
}, executorService);
//任务组合
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(task, task2, task3);
//只要有一个有任务完成
Object o = anyOf.get();
System.out.println("完成的任务的结果:" + o);
}