在Java中并行化for循环

时间:2019-03-28 11:03:06

标签: java multithreading for-loop parallel-processing

我有一个for循环,该循环遍历集合列表。在循环内部,对集合进行了一些选择/更新查询,这些查询不包含其他集合。由于每个集合都有大量数据要处理,因此我想对其进行并行化。

代码段如下所示:

//Some variables that are used within the for loop logic
 for(String collection : collections) {
    //Select queries on collection
    //Update queries on collection
}

如何在Java中实现这一目标?

3 个答案:

答案 0 :(得分:2)

您可以使用parallelStream()方法(自Java 8起):

collections.parallelStream().forEach((collection) -> {
    //Select queries on collection
    //Update queries on collection
});

有关streams的更多信息。


另一种方法是使用执行程序:

    try
    {
        final ExecutorService exec = Executors.newFixedThreadPool(collections.size());
        for (final String collection : collections)
        {
            exec.submit(() -> {
                // Select queries on collection
                // Update queries on collection
            });
        }

        // We want to wait that the jobs are done.
        final boolean terminated = exec.awaitTermination(500, TimeUnit.MILLISECONDS);
        if (terminated == false)
        {
            exec.shutdownNow();
        }

    } catch (final InterruptedException e)
    {
        e.printStackTrace();
    }

此示例功能更强大,因为您可以轻松知道何时完成工作,强制终止... and more

答案 1 :(得分:0)

final int numberOfThreads = 32;

final ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);

// List to store the 'handles' (Futures) for all tasks:
final List<Future<MyResult>> futures = new ArrayList<>();

// Schedule one (parallel) task per String from "collections":
for(final String str : collections) {
  futures.add(executor.submit(() -> { return doSomethingWith(str); }));
}


// Wait until all tasks have completed:
for ( Future<MyResult> f : futures ) {
  MyResult aResult = f.get(); // Will block until the result of the task is available.
  // Optionally do something with the result...
}

executor.shutdown(); // Release the threads held by the executor.

// At this point all tasks have ended and we can continue as if they were all executed sequentially

根据需要调整numberOfThreads,以实现最佳吞吐量。更多线程将倾向于更好地利用本地CPU,但可能会导致远程端产生更多开销。为了获得良好的本地CPU利用率,您希望拥有比CPU(/ core)多得多的线程,以便每当一个线程必须等待时,例如对于DB的响应,可以切换另一个线程以在CPU上执行。

答案 2 :(得分:0)

您需要问自己几个问题才能找到正确的答案:

  

如果我的线程数与CPU内核数一样多,那就足够了吗?

使用parallelStream()将为您提供与CPU内核一样多的线程。

  

并行化循环会提高性能还是DB上存在瓶颈?

您可以启动100个线程,以并行方式进行处理,但这并不意味着如果您的数据库或网络无法处理该卷,您的处理速度将提高100倍。数据库锁定在这里也可能是一个问题。

  

我需要按特定顺序处理数据吗?

如果必须按特定顺序处理数据,这可能会限制您的选择。例如。 forEach()不保证将按照特定顺序处理集合中的元素,但是forEachOrdered()可以(以性能成本为准)。

  

我的数据源是否能够以反应方式获取数据?

在某些情况下,我们的数据源可以以流的形式提供数据。在这种情况下,您始终可以使用RxJavaWebFlux之类的技术来处理此流。这将使您能够对问题采取不同的方法。

综上所述,您可以选择所需的方法(执行程序,RxJava等)更适合您的目的。