【问题标题】:How to use multiple threads in Java to iterate over a Collection where no two threads ever iterate over the same part of the Collection?如何在 Java 中使用多个线程来迭代一个集合,其中没有两个线程曾经迭代过集合的同一部分?
【发布时间】:2015-05-05 13:22:45
【问题描述】:

我需要迭代一个大的 ArrayList(约 50,000 个条目),并且我需要使用多个线程来相当快地完成这项工作。

但是我需要每个线程都从一个唯一的索引开始,这样就不会有两个线程遍历列表的同一部分。将有一个batchSize100,因此每个线程将从其startIndex 循环到startIndex + 100

有什么方法可以实现吗?请注意,我在这里只执行读取操作,没有写入。列表中的每个条目只是一个字符串,它实际上是一个 SQL 查询,然后我通过 JDBC 对数据库执行该查询。

【问题讨论】:

  • 你使用什么类型的收藏?
  • 可以用java 8 .stream().parallel()吗?
  • 您可以先拆分它们并将子列表传递给执行数据库调用的workerThreads
  • 来自上一个答案“再考虑一下,也许您可​​以使用 ForkJoinPool 并分叉多个线程,每个线程都经过一批 100 并加入线程的结果。” FWIW :)

标签: java multithreading collections iteration


【解决方案1】:

如果您只打算读取List,而不是对其进行变异,您可以简单地定义您的Runnable 以将ListstartIndex 作为构造函数参数。只要没有线程同时修改它,同时读取ArrayList(即使是相同的索引)也不会有危险。

为了安全起见,请务必将您的 ArrayList 包含在对 Collections.unmodifiableList() 的调用中,并将 那个 List 传递给您的 Runnables。这样您就可以确信线程不会修改支持 ArrayList

或者,您可以在主线程中构造子列表(使用List.subList()),这样您就不需要将startIndex 传递给每个线程。但是,您仍然希望在这样做之前使子列表不可修改。六个一个,六个另一个。

更好的是使用GuavaImmutableList;它自然是线程安全的。

Java 8 中也有 parallel streams,但请注意这个解决方案;它们很强大,但很容易出错。

【讨论】:

    【解决方案2】:

    如果你使用 Java 8,请查看list.stream().parallel()

    对于 Java 7,在线程外使用 subList() 将工作拆分为多个部分。然后线程应该只对这样的子列表进行操作。对于大多数列表,subList() 是一种非常有效的操作,它不会复制数据。如果备份列表被修改,那么你会得到一个ConcurrentModificationException

    由于将数据泵送到线程,我建议查看Executor API 和Queues。只需将所有工作都放入队列中,让执行者解决所有问题。

    【讨论】:

      【解决方案3】:

      有一个原子变量:

      int nextBatch = 0;
      

      每次线程处理一个新批次时增加它:

      public synchronized int getNextBatch() {
          nextBatch += batchSize;
          if(nextBatch >= arraylist.size()) {
              // The end was reached
              return -1;
          }
          return nextBatch;
      }
      

      线程将调用此方法并获取我们需要处理的范围:

      int start = getNextBatch();
      if(start == -1) {
          // The end was reached
      }
      int end = Math.min(start + batchSize, arraylist.size);
      
      // Iterate over its own range
      for(int i = start; i < end; i++) {
          Object obj = arraylist.get(i);
          // Do something with obj
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-15
        • 2023-01-12
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        • 2022-01-02
        • 2015-08-23
        相关资源
        最近更新 更多