Java ForkJoinPool线程未完成

时间:2018-10-23 13:13:39

标签: java multithreading parallel-processing java-stream forkjoinpool

我正在尝试使用Java流和ForkJoinPool并行化for循环,以控制使用的线程数。当使用单线程运行时,并行化代码返回与顺序程序相同的结果。顺序代码是一组标准的for循环:

for(String file : fileList){
    for(String item : xList){
        for(String x : aList) {
              // action code
        }
    }
}

以下是我的并行实现:

ForkJoinPool threadPool = new ForkJoinPool(NUM_THREADS);
int chunkSize = aList.size()/NUM_THREADS;

for(String file : fileList){
    for(String item : xList){
    IntStream.range(0,  NUM_THREADS)
        .parallel().forEach(i -> threadPool.submit(() -> {

          aList.subList(i*chunkSize, Math.min(i*chunkSize + chunkSize -1, aList.size()-1))
               .forEach(x -> {
                      // action code
                });
          }));

         threadPool.shutdown();
         threadPool.awaitTermination(5, TimeUnit.MINUTES);
    }
}

使用多个线程时,仅完成有限数量的迭代。我尝试使用.shutdown().awaitTermination()来确保所有线程的完成,但是这似乎不起作用。每次运行之间发生的迭代次数差异很大(0-1500之间)。

注意::我使用的Macbook Pro具有8个可用内核(4个双核),并且我的操作代码不包含使并行化不安全的引用。

任何建议将不胜感激,谢谢!

1 个答案:

答案 0 :(得分:1)

我认为您遇到的实际问题是由您在shutdown上致电ForkJoinPool引起的。如果您查看Javadoc,这将导致“有序关闭,在该关闭中将执行先前提交的任务,但不会接受任何新任务”-即。我希望只完成一项任务。

顺便说一句,使用ForkJoinPool的使用方式毫无意义。 ForkJoinPool旨在递归拆分工作负载,这与您在循环中创建子列表不同,但ForkJoinPool应该由RecursiveAction来馈送,后者会自己拆分工作,而不是像循环那样事前将其拆分。不过,这只是一个注释。您的代码应该可以正常运行,但是如果您只是将任务提交给普通的ExecutorService,例如通过Executors.newFixedThreadPool(parallelism)而不是new ForkJoinPool()获得的任务,将会更加清楚。