假设我有以下代码:
CompletableFuture<Integer> future
= CompletableFuture.supplyAsync( () -> 0);thenApply案件:
future.thenApply( x -> x + 1 )
.thenApply( x -> x + 1 )
.thenAccept( x -> System.out.println(x));这里的输出是2,如果是thenApplyAsync的话
future.thenApplyAsync( x -> x + 1 ) // first step
.thenApplyAsync( x -> x + 1 ) // second step
.thenAccept( x -> System.out.println(x)); // third step我在这个博客中看到,每个thenApplyAsync都是在一个单独的线程中执行的,并且“同时执行”(这意味着在thenApplyAsyncs完成之前执行thenApplyAsyncs ),如果是这样的话,如果第一步没有完成,那么第二步的输入参数值是多少?
如果第二步不采取,第一步的结果将如何?第三步将采取哪一步的结果?
如果第二步必须等待第一步的结果,那么Async的意义是什么?
这里,x -> x+1只是为了说明这一点,我想知道的是在非常长的计算情况下。
发布于 2017-11-25 19:15:31
这种区别与负责运行代码的Executor有关。CompletableFuture上的每个操作符通常有3个版本。
thenApply(fn) --在调用它的CompleteableFuture定义的线程上运行fn,因此您通常无法知道将在何处执行。如果结果已经可用,它可能立即执行。thenApplyAsync(fn) -不管情况如何,都在环境定义的执行器上运行fn。对于CompletableFuture,这通常是ForkJoinPool.commonPool()。thenApplyAsync(fn,exec) -在exec上运行fn。最终的结果是相同的,但是调度行为取决于方法的选择。
发布于 2018-07-27 15:04:06
你错误地引用了文章的例子,所以你错误地应用了文章的结论。我在你的问题中看到两个问题:
.then___() 的正确用法是什么
在本文中引用的两个示例中,第二个函数必须等待第一个函数完成。无论何时调用a.then___(b -> ...),输入b都是a的结果,无论是否使用名为Async的方法,都必须等待a完成。这篇文章的结论不适用,因为你错引用了它.
本文中的例子实际上是
CompletableFuture<String> receiver = CompletableFuture.supplyAsync(this::findReceiver);
receiver.thenApplyAsync(this::sendMsg);
receiver.thenApplyAsync(this::sendMsg); 注意,thenApplyAsync都应用于receiver,而不是链接在同一个语句中。这意味着两个函数都可以在receiver完成后以未指定的顺序启动。(任何顺序假设都取决于实现。)
更清楚地说,:
a.thenApply(b).thenApply(c);表示顺序是a完成,然后是b启动,b结束,然后是c启动。
a.thenApplyAsync(b).thenApplyAsync(c);在a b c之间的排序方面将与上面的行为完全相同。
a.thenApply(b); a.thenApply(c);的意思是a完成,然后b或c可以按任何顺序开始。b和c不需要等待对方。
就订单而言,a.thenApplyAync(b); a.thenApplyAsync(c);的工作方式是相同的。
在阅读下面的内容之前,你应该了解上面的内容。上面提到的是异步编程,如果没有异步编程,您将无法正确地使用API。下面涉及线程管理,您可以使用它优化程序并避免性能缺陷。但是,如果不正确地编写程序,就无法优化程序。
名为:thenApply 与 thenApplyAsync of Java CompletableFuture?之间的差异
我必须指出,编写JSR的人肯定混淆了“异步编程”这一技术术语,并选择了现在混淆新手和老手的名字。首先,thenApplyAsync中没有什么比这些方法的契约中的thenApply更异步的了。
两者之间的区别与在哪个线程上运行函数有关。提供给thenApply 可以在任何线程上运行。的函数
completethenApply而thenApplyAsync的2个重载
Executor (a.k.a )。),或Executor对于thenApply,运行时承诺最终使用一些您无法控制的执行器运行您的函数。如果要控制线程,请使用异步变体。
如果您的函数是轻量级的,那么哪个线程运行您的函数并不重要。
如果您的函数是沉重的CPU绑定,则不希望将其留给运行时。如果运行时选择网络线程来运行您的函数,则网络线程无法花费时间来处理网络请求,从而导致网络请求在队列中等待更长时间,而您的服务器将变得没有响应。在这种情况下,您希望在自己的线程池中使用thenApplyAsync。
有趣的事实:异步!=线程
thenApply/thenApplyAsync及其对应的thenCompose/thenComposeAsync、handle/handleAsync、thenAccept/thenAcceptAsync都是异步的!这些函数的异步性质与异步操作最终调用complete或completeExceptionally这一事实有关。这个想法来自Javascript,它确实是异步的,但不是多线程的。
发布于 2017-11-25 19:09:17
这就是文档中对CompletableFuture's thenApplyAsync的看法。
返回一个新的CompletionStage,当这个阶段正常完成时,它将使用这个阶段的默认异步执行工具执行,这个阶段的结果作为提供的函数的参数。
因此,thenApplyAsync必须等待前面的thenApplyAsync's结果:
在您的示例中,首先执行同步工作,然后执行异步工作。因此,第二个是异步的并不重要,因为它只在同步工作完成之后才启动。
我们换一下吧。在某些情况下,“异步结果: 2”将首先打印,在某些情况下,“同步结果: 2”将首先打印。这里的情况有所不同,因为调用1和2都可以异步运行,在单独的线程上调用1,在其他线程上调用2,这可能是主线程。
CompletableFuture<Integer> future
= CompletableFuture.supplyAsync(() -> 0);
future.thenApplyAsync(x -> x + 1) // call 1
.thenApplyAsync(x -> x + 1)
.thenAccept(x -> System.out.println("async result: " + x));
future.thenApply(x -> x + 1) // call 2
.thenApply(x -> x + 1)
.thenAccept(x -> System.out.println("sync result:" + x));https://stackoverflow.com/questions/47489338
复制相似问题