我想同时运行两个具有不同返回类型的方法。下面是我的代码:
public void method(int id) {
final CompletableFuture<List<FooA>> fooACF = CompletableFuture.supplyAsync(() -> generateFooA(id));
final CompletableFuture<List<FooB>> fooBCF = CompletableFuture.supplyAsync(() -> generateFooB(id));
List<FooA> fooAs = fooACF.get();
List<FooB> fooBs = fooBCF.get();
//Do more processesing
}
public List<FooA> generateFooA(int id) {
//code
}
public List<FooB> generateFooB(int id) {
//code
}
但我不知道这两个方法是否会与上面的代码并行运行,或者我最好还是说:
List<FooA> fooAs = generateFooA(id);
List<FooB> fooBs = generateFooB(id);
如何正确地使用可完成future来并行运行这两种方法?
4条答案
按热度按时间w1e3prcc1#
您的代码使用
ForkJoinPool.commonPool()
提供的线程运行良好,正如JavaDoc forCompletableFuture.supplyAsync(Supplier<U> supplier)
所承诺的那样。您可以通过添加一些sleep()
和println()
语句来快速地证明这一点。我使用String
而不是List<Foo>
来稍微简化您的代码:输出为:
您可以手动观察到"离开"输出行在1秒和2秒后出现。为了获得更多证据,您可以向输出添加时间戳。如果更改睡眠的相对长度,您将看到"离开"输出以不同的顺序出现。
如果忽略
sleep()
s,那么第一个线程很可能会很快完成,以至于在第二个线程开始之前就完成了:请注意,这一切发生得如此之快,以至于在运行时请求第二个线程时,该线程已经返回到池中,因此原始线程被重用。
这也可能发生在很短的睡眠中,尽管在我的系统上,每次运行它时1ms的睡眠就足够了。当然,
sleep()
是一个占位符,代表一个需要时间才能完成的"真正的"操作。如果你的真正操作是如此便宜,以至于它在其他线程启动之前就完成了,这是一个很好的暗示,表明在这种情况下多线程是没有好处的。也许你希望通过多线程来提高速度--如果是这样的话,速度的提高应该是你所衡量的,而不是事情是否实际上是并发的。记住,对于大量的任务,CPU不能并行地比顺序地执行它们更快。
xxe27gdn2#
你可以用Java 8+和流API来实现。
例如,我们有一个计算流程如下:
结果=(a + B)+(a-c)+(c * b).
因此,我们将此计算分为以下几种方法:
**注意:**您可以看到,对于每种方法,计算出的过程持续时间为2秒。
Lagacy代码样式:
使用(ExecutorService或Thread)的并行计算:
使用Java8+流进行并行计算:
vql8enpb3#
您缺少一个
Executor
:Runnables
在你submit
它们的时候开始执行。get()
尽快返回。例如,如果你get()
的第一个未来调用是最慢的,所有其他的get()
调用将立即返回。58wvjzkj4#
正如我在我的评论中所说,看看How to start two threads at "exactly" the same time,但这应该是你要找的