1、异步任务创建
在CompletableFuture中提供了四个静态方法用于创建异步任务
runAsync(Runnable runnable)
runAsync(Runnable runnable,Executor executor)
supplyAsync(Supplie<U> supplier)
supplyAsync(Supplier<U> supplier,Executor executor)
1.1 runAsync()应用与源码解析
根据源码可知,runAsync()分为一个参数和两个参数,并且其内部都会调用asyncRunStage()。
在该方法内部会创建异步任务,并把任务放入线程池中。并且runAsync()是没有返回值的。
根据源码可知,当传入Executor会使用指定线程池执行,如果没有传入则使用默认ForkJoinPool.commonPool()执行,值得注意的是,commonPool中都是守护线程,主线程执行完,子线程也就over了。因此建议当任务非常耗时,使用自定义线程池。
//未设置Executor
public class RunAsyncDemo {
public static void main(String[] args) {
CompletableFuture<Void> child_run = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println("child run");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("main end");
}
}
根据结果可以看到,子线程没有来得及打印,主线程就结束了。
//设置自定义线程池
public class RunAsyncDemo2 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(100);
CompletableFuture<Void> child_run = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child run");
}, executorService);
System.out.println("main end");
}
}
根据结果可以看到,就算主线程执行完,但并不会关闭子线程,子线程结果一样可以输出。
1.2 supplyAsync()应用与源码解析
根据源码可知,supplyAsync()分为一个参数和两个参数,并且其内部都会调用asyncSupplyStage()。
现在可知,其实supplyAsync()与runAsync()内部原理类似,但supplyAsync()有返回值。
public class supplyAsyncDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child run");
return 123;
}, executorService);
System.out.println("main end");
Integer integer = future.get();
System.out.println(integer);
executorService.shutdown();
}
}
2、异步计算结果触发回调
当异步任务结束或者抛出异常时,还要根据结果来完成特定的操作,对于这种需求CompletableFuture也提供了方法进行实现。
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(null, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(asyncPool, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action, Executor executor) {
return uniWhenCompleteStage(screenExecutor(executor), action);
}
public CompletableFuture<T> exceptionally(
Function<Throwable, ? extends T> fn) {
return uniExceptionallyStage(fn);
}
2.1 whenComplete()与whenCompleteAsync()使用与源码解析
根据源码可知,上述三个方法都会接收BiConsumer并调用uniWhenCompleteStage,BiConsumer用于定义后续处理业务,处理正常计算结果或异常情况。uniWhenCompleteStage主要用于判断任务执行状态以及构建任务。
值得注意的一点是,whenComplete是在当前任务线程中继续执行指定的特定处理,而whenCompleteAsync会将指定的任务交给线程池另开启一个线程来执行。
// 使用whenComplete
public class whenCompleteDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(100);
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务线程:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child run");
return 123;
}, executor);
future.whenComplete((integer, throwable) -> {
System.out.println("结果触发任务线程:" +Thread.currentThread().getName());
System.out.println("特定任务执行");
});
executor.shutdown();
System.out.println("main end");
}
}
执行结果:
main end
异步任务线程:pool-1-thread-1
child run
结果触发任务线程:pool-1-thread-1
特定任务执行
根据执行结果可知,异步任务结束后,当使用whenComplete()时,后续的特定处理任务使用的线程与异步任务线程相同。
// 使用whenCompleteAsync()
public class whenCompleteAsyncDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(100);
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务线程:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child run");
return 123;
}, executor);
CompletableFuture<Integer> future1 = future.whenCompleteAsync((integer, throwable) -> {
System.out.println("结果触发任务线程:" + Thread.currentThread().getName());
System