Multithreading 如何从与CompletableFutures关联的线程中发出已完成或已取消的信号?
我读了很多关于CompletableFutures的书,他们关注的是一个事实,即CompletableFutures和Future一样,无法访问底层的计算代码。那么,如何从与completableFuture关联的任何任务中发出complete()或cancel()信号(或者检查isCancelled(),如果您想从外部中断计算) 编辑:让我感到困惑的一件事是,CF的可组合性或手动可设置性都超过了其他选项,在我看来,如果实现的话,这两个选项是非常正交的,如:Multithreading 如何从与CompletableFutures关联的线程中发出已完成或已取消的信号?,multithreading,java-8,java.util.concurrent,completable-future,Multithreading,Java 8,Java.util.concurrent,Completable Future,我读了很多关于CompletableFutures的书,他们关注的是一个事实,即CompletableFutures和Future一样,无法访问底层的计算代码。那么,如何从与completableFuture关联的任何任务中发出complete()或cancel()信号(或者检查isCancelled(),如果您想从外部中断计算) 编辑:让我感到困惑的一件事是,CF的可组合性或手动可设置性都超过了其他选项,在我看来,如果实现的话,这两个选项是非常正交的,如: CompletableFuture.
CompletableFuture.runAsync(() -> {
if(myCondition) CF_REF?.complete();
else CF_REF?.exceptionally();
}).thenApply(() -> {
if (myOtherCondition) CF_REF_2?.complete();
(...)
以一种不同时是“可完成的”+“可组合的”的方式设计它有什么意义
我想找到一种方法来使用它们,就像CF使用了一个类似于假设的CompletableCallable的接口作为输入一样,但不知道如何使用。类似于Function
而不是Callables/Runnables,因此我们可以将其用作:
CompletableFuture CF_REF_BIS = CompletableFuture.runAsync((CF_REF) -> {
if(myCondition) CF_REF.complete();
else CF_REF.exceptionally();
});
CF_REF_BIS.thenApply(...)
当要计算代码时,内部执行机制将返回CF_REF_BIS引用,作为在将来的计算中实际作为CF_REF传递的引用,而不需要访问跨范围的引用
这意味着我们可以重新使用一个反匿名的计算代码
只需创建新的CompletableCallable(),然后在任何线程可以访问CompletableFuture信号量的地方提交n次即可
例如:
CompletableFuture CF_REF = CompletableFuture.runAsync(myCompletableCallable)
.thenApply(myCompletableCallable) //again
.thenApply(anotherCompletableCallable);
有没有办法满足这种需求?我忘了什么吗?我的方法有没有根本的不一致?Java CompletableFuture是否仍然是一种半方便的设计?看看javadoc: 如果尚未完成,则设置
get()
和相关
方法设置为给定值
如果尚未完成,则使用
取消异常
。依赖的CompletableFuture
s未完成的
已完成的也将例外完成,包括
CompletionException
由此CancellationException
引起
[……]
参数:
可能中断fRunning-此值在此实现中无效,因为中断不用于控制处理
CompletableFuture
对象与任何可能具有可访问引用的线程完全无关。换句话说,这些对象不是用来给线程发信号的。这种类型的未来基本上是结果的持有者,可以选择注册监听器
whenXyz
和thenAbc
的所有行为都注册到CompletableFuture
对象中。该行为何时执行取决于许多因素:未来哪个线程完成(成功或异常),是否使用*Async
方法注册continuations,等等。这在中进行了说明
例如,创建一个
CompletableFuture
,并将其交给一些线程。据推测,其中一个线程将完成它。这对其他线程没有影响。他们仍然继续做他们正在做或试图做的事情
public static void main(String[] args) throws Exception {
CompletableFuture<String> promise = new CompletableFuture<>();
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable action = () -> {
if (promise.complete("done")) {
System.out.println("completed by " + Thread.currentThread());
} else {
System.out.println("somebody got there first");
}
};
executorService.submit(action);
executorService.submit(action);
executorService.submit(action);
executorService.shutdown();
executorService.awaitTermination(100, TimeUnit.MILLISECONDS);
System.out.println(promise.get());
}
publicstaticvoidmain(字符串[]args)引发异常{
CompletableFuture promise=新的CompletableFuture();
ExecutorService ExecutorService=Executors.newFixedThreadPool(3);
可运行操作=()->{
如果(承诺完成(“完成”)){
System.out.println(“由”+Thread.currentThread()完成);
}否则{
System.out.println(“某人首先到达那里”);
}
};
执行服务。提交(操作);
执行服务。提交(操作);
执行服务。提交(操作);
executorService.shutdown();
执行器服务。等待终止(100,时间单位。毫秒);
System.out.println(promise.get());
}
1)哇,考虑到referer代码将在一个单独的线程中执行,我没有假设您可以像那样在主线程中引用promise var。2) 我读过的其他每一个例子都通过supply/runAsync使用CompletableFutures,在可调用代码的实例化过程中,您如何引用其自身的承诺?。3) 如果不使用lambdas,是否需要将可调用/可运行任务的CF-in构造函数作为每个线程的简单信号传递?那么,它有什么了不起的地方,人们说它是Scala的未来之路呢?通过SupplySync
和runAsync
,你可以获得一个完整的未来。它不一定已经完成了。您仍然可以将它交给另一个线程,并让该线程完成它。你可以用任何合适的方式传递未来:构造函数参数、局部变量捕获等等。我不知道你所说的简单信号量是什么意思。我相信Scala有future
和Promise
。Java的CompletableFuture
是两者的组合。@whimmusical:如果只使用runAsync
和supplyAsync
,在ExecutorService
上调用submit
,获得Future
,没有区别。因此,CompletableFuture
和Future
之间的主要区别已经通过它的名称给出了,您可以显式地完成它,如本答案所示。这是否与“Scala的做法”有关,我不知道(也不在乎)。它对某些任务很有用,但我不会重写所有与并发相关的代码,现在使用CompletableFuture
…