Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 8并行运行多个方法_Java_Concurrency_Java 8_Java.util.concurrent_Completable Future - Fatal编程技术网

Java 8并行运行多个方法

Java 8并行运行多个方法,java,concurrency,java-8,java.util.concurrent,completable-future,Java,Concurrency,Java 8,Java.util.concurrent,Completable Future,我有两个方法,它们有不同的返回类型,我想同时运行。这是我的密码: public void method(int id) { final CompletableFuture<List<FooA>> fooACF = CompletableFuture.supplyAsync(() -> generateFooA(id)); final CompletableFuture<List<FooB>> fooBCF = Completa

我有两个方法,它们有不同的返回类型,我想同时运行。这是我的密码:

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
}
公共无效方法(int-id){
final CompletableFuture fooACF=CompletableFuture.supplyAsync(()->generateFooA(id));
final CompletableFuture fooBCF=CompletableFuture.supplyAsync(()->generateFooB(id));
List fooAs=fooACF.get();
List fooBs=fooBCF.get();
//多加工
}
公共列表生成器OA(int id){
//代码
}
公共列表GenerateFob(int id){
//代码
}
但我不知道这两种方法是与上述代码并行运行,还是说:

List<FooA> fooAs = generateFooA(id);
List<FooB> fooBs = generateFooB(id);
List fooAs=generateFooA(id);
列表fooBs=generateFooB(id);

我如何正确地使用CompletableFutures来并行运行这两种方法?

正如我在评论中所说,请查看,但这应该是您需要的

final CyclicBarrier gate = new CyclicBarrier(3);
public void method(int id) {
    Thread one = new Thread (()->{
        gate.await();
        List<FooA> fooAs = generateFooA(id);
    });
    Thread two = new Thread (()->{
        gate.await();
        List<FooB> fooBs = generateFooB(id);
    });
    one.start();
    two.start();
    gate.await();
    //Do more processesing
}

public List<FooA> generateFooA(int id) {
    //code
}

public List<FooB> generateFooB(int id) {
    //code
}
final CyclicBarrier gate=新的CyclicBarrier(3);
公共void方法(int-id){
线程一=新线程(()->{
门。等待();
列表fooAs=generateFooA(id);
});
线程二=新线程(()->{
门。等待();
列表fooBs=generateFooB(id);
});
一、启动();
二、启动();
门。等待();
//多加工
}
公共列表生成器OA(int id){
//代码
}
公共列表GenerateFob(int id){
//代码
}

您缺少一个
执行者

ExecutorService executor = Executors.newCachedThreadPool();
List<Future<?>> = Stream.<Runnable>of(() -> generateFooA(id), () -> generateFooA(id))
        .map(executor::submit)
        .collect(Collectors.toList());
for (Future<?> future : futures) {
    future.get(); // do whatever you need here
}
ExecutorService executor=Executors.newCachedThreadPool();

列出您的代码工作正常,使用
ForkJoinPool.commonPool()
提供的线程,正如JavaDoc为
CompletableFuture.supplyAsync(供应商)
所承诺的那样。通过添加一些
sleep()
println()
语句,您可以快速而肮脏地证明这一点。通过使用
字符串
而不是
列表
,我简化了您的代码:

您可以手动观察“离开”输出行在1秒和2秒后出现。要获得更多证据,可以向输出中添加时间戳。如果更改睡眠的相对长度,您将看到“离开”输出以不同的顺序出现


如果省略
sleep()
s,那么第一个线程很可能会很快完成,在第二个线程开始之前就完成了:

Entering generateA Thread[ForkJoinPool.commonPool-worker-1,5,main]
Leaving generateA
Entering generateB Thread[ForkJoinPool.commonPool-worker-1,5,main]
Leaving generateB
Final fooA A1
Final fooB B1
请注意,这一切发生得太快了,以至于在运行时请求第二个线程时,线程已经返回到池中。因此,原始线程被重用

这也可能发生在睡眠时间很短的情况下,尽管在我的系统中,每次运行1毫秒的睡眠就足够了。当然,
sleep()
是一个需要时间才能完成的“真实”操作的占位符。如果您的实际操作非常便宜,以至于在另一个线程启动之前就完成了,这就很好地暗示了这是一个多线程没有好处的场景


然而如果你需要问如何证明事情是同时发生的,我想知道你为什么希望事情同时发生。如果当您的程序同时或按顺序执行这些任务时,您的程序之间没有“真实世界”可观察到的差异,那么为什么不让它按顺序运行呢?更容易对顺序操作进行推理;有很多与并发相关的秘密bug


也许你希望通过多线程来提高速度——如果是这样,那么速度的提高应该是你所测量的,而不是事情是否真的是并发的。请记住,对于大量的任务,CPU不能以并行方式比顺序方式更快地执行这些任务。

查看这篇文章,您的代码看起来不错。你有什么特别的担心吗?如果你问你所做的是否会在两个单独的线程上运行这两个方法,那么是的,你正确地使用了
CompletableFuture
。启动另外两个线程并使用
CompletableFuture
毫无意义。
generateFooA(id)
调用和
generateFooB(id)
调用可能正在进行中,运行在不同的线程中,在您的
一个线程或
两个线程到达
门之前。wait()
调用。您似乎认为调用
get()
正在启动任务,但任务被安排在
supplyAsync
内。即使没有人调用
get()
join()
,它们也会一直运行到完成。除此之外,“完全同时”跑步根本不是一个有用的目标。即使您设法同时启动两个任务,它们也可能在下一纳秒内不同步。关于执行时间或线程调度没有任何保证。如何访问
fooAs
fooBs
并对其进行更多处理?例如,“您缺少了一个
执行器
执行器
在OP的示例中是隐含的。该示例将任务提交到
ForkJoinPool.commonPool()
@James,这不是一回事。执行器尽最大努力并行执行,而这段代码独占使用它,所以并行执行是“可能的”。但是ForkJoinPool.commonPool()在所有流之间共享,因此并行执行的可能性较小(但并非不可能或理所当然)。这两种方法都“尽最大努力”并行执行,但是,即使您为每个任务创建了不同的线程,您也永远无法保证并行执行。但即使使用线程池执行器也不能保证这一点。当第一个工作线程设法在提交第二个任务之前完成第一个任务时,它将接收第二个任务(这并不重要)。如果F/J的公共池由于其他任务而没有可用容量,则意味着工作负载占用了所有cpu核心,因此提交线程可能不会在这两个任务之间运行…@Holger of c
Entering generateFooA Thread[ForkJoinPool.commonPool-worker-1,5,main]
Entering generateFooB Thread[ForkJoinPool.commonPool-worker-2,5,main]
Leaving generateFooB
Leaving generateFooA
Final fooA A1
Final fooB B1
Entering generateA Thread[ForkJoinPool.commonPool-worker-1,5,main]
Leaving generateA
Entering generateB Thread[ForkJoinPool.commonPool-worker-1,5,main]
Leaving generateB
Final fooA A1
Final fooB B1