使用CompletableFuture
感觉这玩意和JS
的Promise
很像。先来回顾下如何使用:
CompletableFuture.supplyAsync(()->{
return 1;
}).thenAccept((result)->{
System.out.println(result);
}).exceptionally((e)->{
System.out.println(e);
return null;
});
首先CompletableFuture
这个类来自于java.util.concurrent
包。我们想要使用直接调用其静态方法supplyAsync(Supplier<U> supplier)
就行。
supplyAsync
会通过ForkJoinPool.commonPool()
线程池启动一个工作线程来执行我们传入的supplier
,然后将结果返回。
接下来就可以使用thenAccept(Consumer<? super T> action)
来处理supplyAsync
方法正常执行完毕返回的结果。
然后还会使用exceptionally(Function<Throwable, ? extends T> fn)
来处理supplyAsync
方法执行时出现的异常。
thenAccept
和exceptionally
之间只可能执行其中一个。
需要注意的是,CompletableFuture
所执行的任务都被设定为守护线程,这意味着主线程执行完毕时,它即使没有执行完毕,程序也会关闭。
下面开始说重点:
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 1 / 1;
}).thenAccept((r) -> {
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().isDaemon());
});
Thread.sleep(100);
注意:大概有两种情况:
supplyAsync
还未完成,而thenAccept
欲获取supplyAsync
返回值时,thenAccept
则会将此后续任务放入栈中,由supplyAsync
将前置任务执行完毕后继续执行后续任务。此时前置任务与后续任务的执行都是在同一个工作线程中执行。
ForkJoinPool.commonPool-worker-1
true
ForkJoinPool.commonPool-worker-1
true
supplyAsync
已完成,thenAccept
则获取supplyAsync
返回值,将后续任务在当前线程执行完毕,因此前置任务在工作线程中执行,而后续任务在当前线程中执行。
ForkJoinPool.commonPool-worker-1
true
main
false
相较于thenAccept
执行线程的不确定性,thenAcceptAsync
执行的后续任务则总是与前置任务在同一个线程执行,也就是前置任务与后置任务都在一个工作线程中执行。
CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 1 / 1;
}).thenAcceptAsync((r) -> {
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().isDaemon());
});
Thread.sleep(100);
/*
ForkJoinPool.commonPool-worker-1
true
ForkJoinPool.commonPool-worker-1
true
*/