CompletableFuture与Future有什么不同
开发背景
对比举例
Future实现
CompletableFuture实现
不同点
相同点
CompletableFuture的基本使用
创建一个异步任务
获取任务结果
任务完成后的回调
thenApplyXXX
thenAcceptXXXX
thenRunXXX
whenCompleteXXX
handleXXX
thenComposeXXX
依赖于两个任务的回调
前置两个任务都完成后
thenCombineXXX
thenAcceptBothXXX
runAfterBothXXX
前置任意一个任务完成后
applyToEitherXXX
acceptEitherXXX
runAfterEitherXXX
举例
依赖于多个任务的回调
任意一个完成后–anyOf
所有任务都完成后–allOf
举例
异常处理
API的分类与总结
三种基本任务类型
三种重载方法
分类
源码解析
如何创建一个任务
thenApply是如何执行的
uniApplyStage
封装函数是如何被执行的
函数式接口在哪里被调用
UniApply源码解析
后续任务是如何被调用的
调用者触发执行
前置任务触发
postFire方法
后续任务的后续任务是如何被执行的
postComplete源码分析
stack整理流程图
allOf、anyOf是如何实现的
@Test
public void FutureExample2() throws ExecutionException, InterruptedException
{
ExecutorService waiters = Executors.newFixedThreadPool( 2 );
ExecutorService cookers = Executors.newFixedThreadPool( 2 );
printTimeAndThread("小白进入餐厅");
printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");
Future makeRice = waiters.submit(() -> {
ThreadTools.sleepSeconds( 2 );
printTimeAndThread("饭好了");
return "米饭";
});
Future cookDish = cookers.submit(() -> {
ThreadTools.sleepSeconds( 2 );
printTimeAndThread("菜好了");
return "番茄炒蛋";
});
Future getRice = waiters.submit(() -> {
final long start = System.currentTimeMillis();
String rice = makeRice.get();
String dish = cookDish.get();
ThreadTools. sleepSeconds( 2 );
printTimeAndThread(String.format("服务员打饭完成,耗时%d",
System.currentTimeMillis() - start));
return String.format("%s + %s 好了", dish, rice);
});
printTimeAndThread("小白在打王者");
printTimeAndThread(String.format("%s ,小白开吃", getRice.get()));
}
1634092703854 | main | 小白进入餐厅
1634092703854 | main | 小白点了 番茄炒蛋 + 一碗米饭
1634092703856 | main | 小白在打王者
1634092705874 | pool-2-thread-1 | 菜好了
1634092705874 | pool-1-thread-1 | 饭好了
1634092707884 | pool-1-thread-2 | 服务员打饭完成,耗时 4028
1634092707885 | main | 番茄炒蛋 + 米饭 好了 ,小白开吃
@Test
public void CPExample2() {
printTimeAndThread("小白进入餐厅");
printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");
CompletableFuture makeRice = CompletableFuture.supplyAsync(() ->
{
sleepSeconds( 2 );
FutureTaskTest.printTimeAndThread("做米饭");
return "米饭";
});
CompletableFuture makeDish = CompletableFuture.supplyAsync(() ->
{
sleepSeconds( 2 );
printTimeAndThread("厨师炒菜");
return "番茄炒蛋";
});
final CompletableFuture allDone = makeDish.thenCombine(makeRice,
(dish, rice) -> {
final long start = System.currentTimeMillis();
sleepSeconds( 2 );
printTimeAndThread(String.format("服务员打饭完成,耗时%d",
System.currentTimeMillis() - start));
return String.format("%s + %s 好了", dish, rice);
});
printTimeAndThread("小白在打王者");
printTimeAndThread(String.format("%s ,小白开吃", allDone.join()));
}
1634822712205 | main | 小白进入餐厅
1634822712205 | main | 小白点了 番茄炒蛋 + 一碗米饭
1634822712207 | main | 小白在打王者
1634822714221 | ForkJoinPool.commonPool-worker-2 | 厨师炒菜
1634822714221 | ForkJoinPool.commonPool-worker-9 | 做米饭
1634822716229 | ForkJoinPool.commonPool-worker-9 | 服务员打饭完成,耗时 2008
1634822716229 | main | 番茄炒蛋 + 米饭 好了 ,小白开吃
public static CompletableFuture runAsync(Runnable runnable)
public static CompletableFuture supplyAsync(Supplier supplier)
public static CompletableFuture runAsync(Runnable runnable,Executor
executor)
public static CompletableFuture supplyAsync(Supplier supplier,Executor
executor)
@Test
public void CompletableFutureStart() {
CompletableFuture.runAsync(() -> {
ThreadTools.sleepSeconds( 1 );
System.out.printf("run on %s %n", Thread.currentThread().getName());
});
CompletableFuture.supplyAsync(() -> {
ThreadTools.sleepSeconds( 2 );
System.out.printf("run on %s %n", Thread.currentThread().getName());
return "success";
});
ThreadTools.sleepSeconds( 5 );
}
run on ForkJoinPool.commonPool-worker- 1
run on ForkJoinPool.commonPool-worker- 2
public T get()
public T get(long timeout, TimeUnit unit)
public T getNow(T valueIfAbsent)
public T join()
@Test
public void CompletableFutureGet() {
try {
final Void unused = CompletableFuture.runAsync(() -> {
ThreadTools.sleepSeconds( 1 );
System.out.printf("run on %s %n", Thread.currentThread().getName());
}).get();
System.out.println("CompletableFuture task 1 result "+unused);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
final String result = CompletableFuture.supplyAsync(() -> {
ThreadTools.sleepSeconds( 2 );
System.out.printf("run on %s %n", Thread.currentThread().getName());
return "success";
}).join();
System.out.println("CompletableFuture task2 result "+result);
ThreadTools.sleepSeconds( 5 );
run on ForkJoinPool.commonPool-worker-
CompletableFuture task 1 result null
run on ForkJoinPool.commonPool-worker-
CompletableFuture task2 result success
public CompletionStage thenApply(Function super T,? extends U> fn);
public CompletionStage thenApplyAsync(Function super T,? extends U>
fn);
public CompletionStage thenApplyAsync(Function super T,? extends U>
fn,Executor executor);
@Test
public void RunTest() {
final CompletableFuture future1 = CompletableFuture.supplyAsync(() -
> "from supply").thenApply(r -> {
System.out.println(r);
return "success";
});
System.out.println(future1.join());
}
public CompletionStage thenAccept(Consumer super T> action);
public CompletionStage thenAcceptAsync(Consumer super T> action);
public CompletionStage thenAcceptAsync(Consumer super T>
action,Executor executor);
public CompletionStage thenRun(Runnable action);
public CompletionStage thenRunAsync(Runnable action);
public CompletionStage thenRunAsync(Runnable action,Executor executor);
public CompletionStage whenComplete(BiConsumer super T,? super Throwable>
action);
public CompletionStage whenCompleteAsync(BiConsumer super T,? super
Throwable> action);
public CompletionStage whenCompleteAsync(BiConsumer super T,? super
Throwable> action,Executor executor);
public CompletionStage handle(BiFunction super T, Throwable,? extends
U> fn);
public CompletionStage handleAsync(BiFunction super T, Throwable,?
extends U> fn);
public CompletionStage handleAsync(BiFunction super T, Throwable,?
extends U> fn,Executor executor);
public CompletionStage thenCompose(Function super T,? extends
CompletionStage> fn);
public CompletionStage thenComposeAsync(Function super T,? extends
CompletionStage> fn);
public CompletionStage thenComposeAsync(Function super T,? extends
CompletionStage> fn,Executor executor);
* thenCompose举例
*/
@Test
public void FutureTaskTestCompose() {
CompletableFuture future1 = CompletableFuture.supplyAsync(() ->
"task 1");
final CompletableFuture future2 =
CompletableFuture.supplyAsync(() -> "next stage");
CompletableFuture nextFuture = future1.thenCompose((result) -> {
System.out.printf("future1 result is \"%s\"%n", result);
return future2;
});
System.out.println(future2 == nextFuture);
final String join = nextFuture.join();
System.out.printf("nextFuture result is \"%s\"%n", join);
}
* thenCompose对比thenApply
*/
@Test
public void FutureTaskTestCompose2() {
CompletableFuture future1 = CompletableFuture.supplyAsync(() ->
"task 1");
final CompletableFuture future2 =
CompletableFuture.supplyAsync(() -> "next stage");
//thenApply返回一个CompletableFuture对象
final CompletableFuture> nextFuture =
future1.thenApply((result) -> {
System.out.printf("future1 result is \"%s\"%n", result);
return future2;
});
final CompletableFuture innerStage = nextFuture.join();//获取到的
结果为CompletableFuture对象
final String result = innerStage.join();//获取返回的CompletableFuture对象执
行的结果
System.out.printf("nextFuture result is \"%s\"%n", result);
}
future1 result is "task 1"
false
nextFuture result is "next stage"
future1 result is "task 1"
nextFuture result is "next stage"
public CompletionStage thenCombine(CompletionStage extends U>
other,BiFunction super T,? super U,? extends V> fn);
public CompletionStage thenCombineAsync (CompletionStage extends U>
other, BiFunction super T,? super U,? extends V> fn);
public CompletionStage thenCombineAsync (CompletionStage extends U>
other, BiFunction super T,? super U,? extends V> fn,Executor executor);
public CompletionStage thenAcceptBoth(CompletionStage extends U>
other,BiConsumer super T,? super U> action);
public CompletionStage thenAcceptBothAsync(CompletionStage extends
U> other,BiConsumer super T,? super U> action);
public CompletionStage thenAcceptBothAsync(CompletionStage extends
U> other,BiConsumer super T,? super U> action, Executor executor);
public CompletionStage runAfterBoth(CompletionStage> other,Runnable
action);
public CompletionStage runAfterBothAsync(CompletionStage> other,Runnable
action);
public CompletionStage runAfterBothAsync(CompletionStage> other,Runnable
action,Executor executor);
public CompletionStage applyToEither(CompletionStage extends T>
other,Function super T, U> fn);
public CompletionStage applyToEitherAsync(CompletionStage extends T>
other,Function super T, U> fn);
public CompletionStage applyToEitherAsync(CompletionStage extends T>
other,Function super T, U> fn,Executor xecutor);
public CompletionStage acceptEither(CompletionStage extends T>
other,Consumer super T> action);
public CompletionStage acceptEitherAsync(CompletionStage extends T>
other,Consumer super T> action);
public CompletionStage acceptEitherAsync(CompletionStage extends T>
other,Consumer super T> action,Executor executor);
public CompletionStage runAfterEither(CompletionStage> other,Runnable
action);
public CompletionStage runAfterEitherAsync(CompletionStage>
other,Runnable action);
public CompletionStage runAfterEitherAsync(CompletionStage>
other,Runnable action,Executor executor);
@Test
public void bothOrAny() {
final CompletableFuture task1 = CompletableFuture.supplyAsync(() ->
{
ThreadTools.sleepSeconds( 1 );
return "task 1";
});
final CompletableFuture task2 = CompletableFuture.supplyAsync(() ->
{
ThreadTools.sleepSeconds( 2 );
return "task 2";
});
//依赖于两个前置任务都完成
final CompletableFuture both = task2.thenAcceptBothAsync(task1, (r1,
r2) -> {
System.out.printf("两个任务都已经完成。结果 1 :%s ,结果2: %s%n", r1, r2);
});
//依赖于两个前置任务,但有一个完成即可
final CompletableFuture any = task1.acceptEitherAsync(task2, (r) -> {
System.out.printf("有一个任务已经完成,结果是:%s%n", r);
});
//阻塞主线程结束
any.runAfterBoth(both, ()->{}).join();
}
有一个任务已经完成,结果是:task 1
两个任务都已经完成。结果 1 :task 2 ,结果2: task 1
public static CompletableFuture
public static CompletableFuture allOf(CompletableFuture>... cfs)
@Test
public void anyANdAll() {
final ExecutorService threadPool = Executors.newFixedThreadPool( 10 );
final long startAll = System.currentTimeMillis();
final CompletableFuture[] completableFutures = IntStream.rangeClosed( 1 ,
10 ).mapToObj(index -> CompletableFuture.supplyAsync(() -> {
final long start = System.currentTimeMillis();
try {
Thread.sleep( 100 * index);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("线程'%s'执行完成,花费%d毫秒%n",
Thread.currentThread().getName(), System.currentTimeMillis() - start);
return index;
}, threadPool)).toArray(CompletableFuture[]::new);
final Object result = CompletableFuture.anyOf(completableFutures).join();
System.out.printf("any of 得到结果:%s,共花费%d毫秒%n", result,
System.currentTimeMillis() - startAll);
CompletableFuture.allOf(completableFutures).join();//阻塞主线程
System.out.printf("all of 得到结果,共花费%d毫秒%n", System.currentTimeMillis()
线程'pool-1-thread-1'执行完成,花费 110 毫秒
any of 得到结果: 1 ,共花费 122 毫秒
线程'pool-1-thread-2'执行完成,花费 205 毫秒
线程'pool-1-thread-3'执行完成,花费 300 毫秒
线程'pool-1-thread-4'执行完成,花费 411 毫秒
线程'pool-1-thread-5'执行完成,花费 505 毫秒
线程'pool-1-thread-6'执行完成,花费 615 毫秒
线程'pool-1-thread-7'执行完成,花费 710 毫秒
线程'pool-1-thread-8'执行完成,花费 804 毫秒
线程'pool-1-thread-9'执行完成,花费 915 毫秒
线程'pool-1-thread-10'执行完成,花费 1011 毫秒
all of 得到结果,共花费 1024 毫秒
public CompletionStage exceptionally(Function fn);
@Test
public void CPExceptional() {
CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("抛出的异常");
}).exceptionally((e) -> {
System.out.printf("异常消息%s%n", e.getMessage());
return "new result";
}).thenAccept(r -> {
System.out.printf("最终结果1:%s%n", r);
});
CompletableFuture.supplyAsync(() -> "没有抛出异常")
.exceptionally((e) -> {
System.out.printf("异常消息%s%n", e.getMessage());
return "new result";
}).thenAccept(r ->
System.out.printf("最终结果2:%s%n", r));
}
异常消息java.lang.RuntimeException: 抛出的异常
最终结果1:new result
最终结果2:没有抛出异常
public static CompletableFuture supplyAsync(Supplier supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
public static CompletableFuture supplyAsync(Supplier
supplier,Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
static CompletableFuture asyncSupplyStage(Executor e,Supplier f) {
if (f == null) throw new NullPointerException();
CompletableFuture d = new CompletableFuture();
e.execute(new AsyncSupply(d, f));//封装Supplier接口并提交到线程池中
return d;
}
static final class AsyncSupply extends ForkJoinTask
implements Runnable, AsynchronousCompletionTask {
CompletableFuture dep; Supplier fn;
AsyncSupply(CompletableFuture dep, Supplier fn) {
this.dep = dep; this.fn = fn;
}
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) {}
public final boolean exec() { run(); return true; }
public void run() {
CompletableFuture d; Supplier f;
if ((d = dep) != null && (f = fn) != null) {
dep = null; fn = null;
if (d.result == null) {
try {
d.completeValue(f.get());//执行supply函数的get方法
} catch (Throwable ex) {
d.completeThrowable(ex);
}
d.postComplete();//调用后续任务
}
}
}
private CompletableFuture uniApplyStage(
Executor e, Function super T,? extends V> f) {
if (f == null) throw new NullPointerException();
CompletableFuture d = new CompletableFuture();
if (e != null || !d.uniApply(this, f, null)) {//判断线程池是否为空,为空则直接尝试
执行
//线程池不为空,或前置任务未完成,需要入栈排队。
UniApply c = new UniApply(e, d, this, f);//新建对象,封装代表执行逻
辑的函数式接口对象f,代表当前阶段的CP对象d,还有前置任务this,以及线程池e;
push(c);//将封装好的任务push到当前CP对象的stack中
c.tryFire(SYNC);//防止push过程中前置任务变更完成状态,漏掉当前阶段的任务。尝试执行
一次。
}
return d;
}
final boolean uniApply(CompletableFuture a,
Function super S,? extends T> f,
UniApply c) {//a前置CP,f当前阶段函数,c封装当前阶
段逻辑的Completion对象
Object r; Throwable x;
if (a == null || (r = a.result) == null || f == null)
return false;//前置任务未完成或其他异常情况
tryComplete: if (result == null) {//当前CP的结果为空
if (r instanceof AltResult) {
if ((x = ((AltResult)r).ex) != null) {
completeThrowable(x, r);//之前任务结果为异常
break tryComplete;
}
r = null;//前置任务结果为空,decode为null
}
try {
if (c != null && !c.claim())//claim判断任务是否被执行过;通过“调用线
程”执行c才是null
return false;
@SuppressWarnings("unchecked") S s = (S) r;
completeValue(f.apply(s));//调用function函数的apply方法,并将结果封装
到CompletableFuture对象中。
} catch (Throwable ex) {
completeThrowable(ex);
}
}
return true;
}
private CompletableFuture uniApplyStage(
Executor e, Function super T,? extends V> f) {
if (f == null) throw new NullPointerException();
CompletableFuture d = new CompletableFuture();
if (e != null || !d.uniApply(this, f, null)) {
UniApply c = new UniApply(e, d, this, f);
push(c);
c.tryFire(SYNC);//前一个阶段已经完成,当前阶段"自己"触发任务执行
}
return d;
}
final CompletableFuture tryFire(int mode) {
CompletableFuture d; CompletableFuture a;
if ((d = dep) == null ||
!d.uniApply(a = src, fn, mode > 0? null : this))//执行当前阶段任务逻辑
return null;
dep = null; src = null; fn = null;
return d.postFire(a, mode);//清理stack、调用后续任务
final CompletableFuture postFire(CompletableFuture> a, int mode) {
if (a != null && a.stack != null) {
if (mode < 0 || a.result == null)//嵌套调用时,清理后续无效节点;非嵌套调用
时,当前阶段已经完成,前置阶段未完成(xxxEither),把当前节点从a的stack中清理出去。见下面例
子。
a.cleanStack();//清理stack中的无效节点
else
a.postComplete();//(非嵌套调用,前置任务a已经完成。可能是异步线程执行完毕
的回调)如果当前阶段任务执行完成,前置任务已经完成,前置任务的stack不为空,使用当前线程帮助前置
任务执行stack
}
if (result != null && stack != null) {
if (mode < 0 )
return this;//嵌套调用,返回当前阶段。
else
postComplete();//非嵌套调用,处理当前阶段的stack
}
return null;
}
CompletableFuture future1 = CompletableFuture.
supplyAsync(() -> {
System.out.println("future1执行完成");
return null;
});
CompletableFuture future2 = CompletableFuture.supplyAsync(() ->
{
ThreadTools.sleepSeconds( 1 );
System.out.println("future2 执行完成");
return "future2 result";
});
future2.thenRun(System.out::println);
future2.acceptEitherAsync(future1, (r) -> System.out.println()).join();
final void postComplete() {
/*
* On each step, variable f holds current dependents to pop
* and run. It is extended along only one path at a time,
* pushing others to avoid unbounded recursion.
* f-->当前CP对象,h-->CP对象的stack,t-->stack的next节点
*/
CompletableFuture> f = this; Completion h;
while ((h = f.stack) != null ||
(f != this && (h = (f = this).stack) != null)) {
CompletableFuture> d; Completion t;
if (f.casStack(h, t = h.next)) {//保证postComplete被并发调用时,同一个任务只能
被一个线程拿到
if (t != null) {
if (f != this) {//下一阶段CP对象的stack不为空,将stack压入当前CP对象的
stack中。防止递归调用过深。
pushStack(h);
continue;
}
h.next = null; // detach
}
f = (d = h.tryFire(NESTED)) == null? this : d;//d-->tryFire的返回值;
d不为空时,f被指向d。即h任务所在阶段的CompletableFuture对象
}
}
}