文章目录
官方文档
A Future that may be explicitly completed (setting its value and
status), and may be used as a CompletionStage, supporting
dependent functions and actions that trigger upon its
completion.
When two or more threads attempt to complete,
completeExceptionally, or cancel a CompletableFuture, only one
of them succeeds.
In addition to these and related methods for directly
manipulating status and results, CompletableFuture implements
interface CompletionStage with the following policies:
* Actions supplied for dependent completions of non-async
methods may be performed by the thread that completes the
current CompletableFuture, or by any other caller of a
completion method.
* All async methods without an explicit Executor argument are
performed using the ForkJoinPool.commonPool() (unless it
does not support a parallelism level of at least two, in which
case, a new Thread is created to run each task). To simplify
monitoring, debugging, and tracking, all generated
asynchronous tasks are instances of the marker interface
CompletableFuture.AsynchronousCompletionTask.
* All CompletionStage methods are implemented independently
of other public methods, so the behavior of one method is not
impacted by overrides of others in subclasses.
CompletableFuture also implements Future with the following
policies:
* Since (unlike FutureTask) this class has no direct control over
the computation that causes it to be completed, cancellation is
treated as just another form of exceptional completion. Method
cancel has the same effect as completeExceptionally(new
CancellationException()). Method isCompletedExceptionally()
can be used to determine if a CompletableFuture completed in
any exceptional fashion.
* In case of exceptional completion with a CompletionException,
methods get() and get(long, TimeUnit) throw an
ExecutionException with the same cause as held in the
corresponding CompletionException. To simplify usage in most
contexts, this class also defines methods join() and getNow(T)
that instead throw the CompletionException directly in these
cases.
可以显式完成的Future(设置其值和状态),并且可以用作CompletionStage,支持在完成时触发依赖函数和操作。
Future的不足
Future是Java5添加的类, 用来描述一个异步计算的结果。你可以使用isDone 方法检查计算是否完成,或者使用 get 阻塞住调用线程,直到计算完成返回结果, 你也可以使用 cancel 方法停止任务的执行。
虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果 的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方 式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的 CPU 资源, 而且也不能及时地得到计算结果,为什么不能用观察者设计模式当计算结果完成 及时通知监听者呢?
Java 的一些框架,比如 Netty,自己扩展了 Java 的 Future 接口,提供了 addListener 等多个扩展方法,Googleguava 也提供了通用的扩展 Future:ListenableFuture、SettableFuture 以及辅助类 Futures 等,方便异步编程。
同时 Future 接口很难直接表述多个 Future 结果之间的依赖性。实际开发中, 我们经常需要达成以下目的:
- 将两个异步计算合并为一个——这两个异步计算之间相互独立,同时第二个 又依赖于第一个的结果。
- 等待 Future 集合中的所有任务都完成。
- 仅等待 Future 集合中最快结束的任务完成(有可能因为它们试图通过不同 的方式计算同一个值),并返回它的结果。
- 应对 Future 的完成事件(即当 Future 的完成事件发生时会收到通知,并 能使用 Future 计算的结果进行下一步的操作,不只是简单地阻塞等待操作的结 果)
CompletableFuture
JDK1.8 才新加入的一个实现类 CompletableFuture,实现了 Future,CompletionStage两个接口。实现了 Future 接口,意味着可以像以 前一样通过阻塞或者轮询的方式获得结果。
创 建
除了直接 new 出一个 CompletableFuture 的实例,还可以通过工厂方法创建 CompletableFuture 的实例
工厂方法:
Asynsc表示异步,而supplyAsync与runAsync不同在与前者异步返回一个结果, 后者是 void.第二个函数第二个参数表示是用我们自己创建的线程池,否则采用默 认的 ForkJoinPool.commonPool()作为它的线程池。
获得结果的方法
public Tget()
public Tget(longtimeout,TimeUnitunit)
public TgetNow(TvalueIfAbsent)
public Tjoin()
getNow 有点特殊,如果结果已经计算完则返回结果或者抛出异常,否则返 回给定的 valueIfAbsent 值。
join 返回计算的结果或者抛出一个 unchecked 异常(CompletionException),它 和 get 对抛出的异常的处理有些细微的区别。
参见代码
/**
* 类说明:CompletableFuture使用范例
*/
public class CFDemo {
static class GetResult extends Thread {
CompletableFuture<Integer> f;
GetResult(String threadName, CompletableFuture<Integer> f) {
super(threadName);
this.f = f;
}
@Override
public void run() {
try {
System.out.println("waiting result.....");
System.out.println(this.getName() + ": " + f.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
final CompletableFuture<Integer> f = new CompletableFuture<>();
new GetResult("Client1", f).start();
new GetResult("Client2", f).start();
System.out.println("sleeping");
SleepTools.second(2);
//f.complete(100);
f.completeExceptionally(new Exception());
System.in.read();
}
}
get和join方法的区别
/**
* 类说明:get和join方法的区别
*/
public class JoinAndGet {
public static void main(String[] args)
throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->{
int i = 1/0;
return 100;
});
//future.get();
future.join();
}
}
辅助方法
public static CompletableFuture<Void>allOf(CompletableFuture<?>...cfs)
public static CompletableFuture<Object>anyOf(CompletableFuture<?>...cfs)
- allOf 方法是当所有的 CompletableFuture 都执行完后执行计算。
- anyOf 方法是当任意一个 CompletableFuture 执行完后就会执行计算,计算的 结果相同。
/**
* 类说明:allOf和anyOf的区别
*/
public class AllofAnyOf {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Random rand = new Random();
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000 + rand.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future1完成");
return 100;
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000 + rand.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future2完成");
return "abc";
});
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000 + rand.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future3完成");
return "123abc";
});
CompletableFuture.allOf(future1,future2,future3).thenRun(()->{
System.out.println("All done!");
});
// CompletableFuture<Object> f = CompletableFuture.anyOf(future1,future2,future3);
// System.out.println(f.get());
SleepTools.second(5);
}
}
CompletionStage 是一个接口,从命名上看得知是一个完成的阶段,它代表 了一个特定的计算的阶段,可以同步或者异步的被完成。你可以把它看成一个计 算流水线上的一个单元,并最终会产生一个最终结果,这意味着几个 CompletionStage 可以串联起来,一个完成的阶段可以触发下一阶段的执行,接 着触发下一次,再接着触发下一次,……….。
总结 CompletableFuture 几个关键点:
- 计算可以由 Future ,Consumer 或者 Runnable 接口中的 apply,accept 或者 run 等方法表示。
- 计算的执行主要有以下
a. 默认执行
b. 使用默认的 CompletionStage 的异步执行提供者异步执行。这些方法名使 用 someActionAsync 这种格式表示。
c. 使用 Executor 提供者异步执行。这些方法同样也是 someActionAsync 这 种格式,但是会增加一个 Executor 参数。
CompletableFuture 里大约有五十种方法,但是可以进行归类
变换类 thenApply
关键入参是函数式接口 Function。它的入参是上一个阶段计算后的结果,返 回值是经过转化后结果。
消费类 thenAccept
关键入参是函数式接口 Consumer。它的入参是上一个阶段计算后的结果, 没有返回值。
执行操作类 thenRun
对上一步的计算结果不关心,执行下一个操作,入参是一个 Runnable 的实 例,表示上一步完成后执行的操作。
结合转化类
需要上一步的处理返回值,并且 other 代表的 CompletionStage 有返回值之 后,利用这两个返回值,进行转换后返回指定类型的值。
两个 CompletionStage 是并行执行的,它们之间并没有先后依赖顺序,other 并不会等待先前的 CompletableFuture 执行完毕后再执行。
结合转化类
对于 Compose 可以连接两个 CompletableFuture,其内部处理逻辑是当第一 个CompletableFuture处理没有完成时会合并成一个CompletableFuture,如果处理 完成,第二个 future 会紧接上一个 CompletableFuture 进行处理。
第一个 CompletableFuture 的处理结果是第二个 future 需要的输入参数。
结合消费类
需要上一步的处理返回值,并且 other 代表的 CompletionStage 有返回值之 后,利用这两个返回值,进行消费
运行后执行类
不关心这两个 CompletionStage 的结果,只关心这两个 CompletionStage 都执 行完毕,之后再进行操作(Runnable)。
取最快转换类
两个 CompletionStage,谁计算的快,我就用那个 CompletionStage 的结果进 行下一步的转化操作。现实开发场景中,总会碰到有两种渠道完成同一个事情, 所以就可以调用这个方法,找一个最快的结果进行处理。
取最快消费类
两个 CompletionStage,谁计算的快,我就用那个 CompletionStage 的结果进 行下一步的消费操作。
取最快运行后执行类
两个 CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)。
异常补偿类
当运行时出现了异常,可以通过 exceptionally 进行补偿。
运行后记录结果类
action 执行完毕后它的结果返回原始的 CompletableFuture 的计算结果或者返回 异常。所以不会对结果产生任何的作用。
运行后处理结果类
运行完成时,对结果的处理。这里的完成时有两种情况,一种是正常执行, 返回值。另外一种是遇到异常抛出造成程序的中断。