示例1:
CometableFuture
.supplyAsync(new MySupplier())
.someCompletableFutureMethod(new SomeCompletableFutureComsumer())
ForkJoin线程是否会被阻止?
示例2:
final CompletableFuture cf = new CompletableFuture();
cf = executor.execute(new Runnable(){
public void run(){
//do work
cf.complete(result);
}
});
cf.whenComplete(new MyConsumer());
所涉及的任何踏板是否都会受阻?
(我知道,我应该使用Callable而不是Runnable:)
有没有办法在不使用Future继承的方法来阻止任何线程(main,ForkJoin,executor)的情况下滥用API?
假设我没有使用任何阻止API(我知道future.get()阻止)。
答案 0 :(得分:3)
请参阅get()
的{{3}}:
如果有必要等待此未来完成,然后返回其结果。
换句话说:当你在CompletableFuture上调用“阻塞”方法时,它应该阻止。否则,它不会。
javadoc中没有方法的描述如下:可能会随机阻止 ;-)!
答案 1 :(得分:3)
CompletableFuture
添加了join()
方法,种类是Future.get()
(docs here)的未经检查的例外版本。
我不建议使用它,因为通过不超时,它可以挂起线程,你几乎总是可以使用thenApply
和朋友重写代码。
我尝试通过始终使用CompletionStage
实现的CompletableFuture
来强制执行此操作。
除了从Future
块继承的方法之外,我不会想到任何其他方法。
答案 2 :(得分:1)
所有这些方法都需要某种形式的同步,如果没有阻塞就无法正确实现。
例如:
supplyAsync()
尝试通过其ForkJoin
方法对公共execute()
池中的作业进行排队。此方法依赖于Unsafe
和awaitRunStateLock()
对作业进行排队; executor.execute()
,但您的实施可能会有所不同; someCompletableFutureMethod()
(和whenComplete()
):
*Async()
方法之外,它首先需要检查这个未来是否已经完成:如果是这种情况,传入的函数将在调用线程上执行,你可能认为它是阻塞的(虽然它实际上是在执行你的代码); Unsafe
来执行此操作 - 请参阅CompletableFuture.*push*(*)
方法。cf.complete()
需要处理子任务,例如发送到whenComplete()
的任务:
CompletableFuture
方法(并返回一个新的CompletableFuture
)实际上隐藏了一个complete()
调用(在返回的将来),该调用将由同一个线程执行执行lambda,因此像4.¹当然,除了在高度并发的环境中,许多线程试图同时推送和执行任务,你可能不会注意到这种阻塞。案例3.1和4.2是您最常遇到的案例(如果您使用非*Async()
方法)。
¹thenCompose()
方法有一个微妙的例外,因为执行complete()
调用的线程将取决于lambda返回的CompletionStage
是否已经完成。此外,非静态*Async()
方法似乎重用了此调用的执行程序,因此可以使用另一个线程。