java:不可变Iterable上的并发迭代

java:不可变Iterable上的并发迭代,java,concurrency,iterator,iterable,Java,Concurrency,Iterator,Iterable,我有一个包含大量元素的不可变Iterable。(它恰好是一个列表,但没关系。) 我想做的是启动一些并行/异步任务,用相同的迭代器在Iterable上迭代,我想知道应该使用什么接口 下面是一个带有待定接口的示例实现QuasiIteratorInterface: public void process(Iterable<X> iterable) { QuasiIteratorInterface<X> qit = ParallelIteratorWrapper.itera

我有一个包含大量元素的不可变
Iterable
。(它恰好是一个
列表
,但没关系。)

我想做的是启动一些并行/异步任务,用相同的迭代器在
Iterable
上迭代,我想知道应该使用什么接口

下面是一个带有待定接口的示例实现
QuasiIteratorInterface

public void process(Iterable<X> iterable)
{
   QuasiIteratorInterface<X> qit = ParallelIteratorWrapper.iterate(iterable);
   for (int i = 0; i < MAX_PARALLEL_COUNT; ++i)
   {
      SomeWorkerClass worker = new SomeWorkerClass(qit);
      worker.start();
   }
}

class ParallelIteratorWrapper<T> implements QuasiIteratorInterface<T>
{
   final private Iterator<T> iterator;
   final private Object lock = new Object();
   private ParallelIteratorWrapper(Iterator<T> iterator) { 
      this.iterator = iterator;
   }
   static public <T> ParallelIteratorWrapper<T> iterate(Iterable<T> iterable)
   {
      return new ParallelIteratorWrapper(iterable.iterator());
   }
   private T getNextItem()
   {
      synchronized(lock)
      {
         if (this.iterator.hasNext())
            return this.iterator.next();
         else
            return null;
      }
   }
   /* QuasiIteratorInterface methods here */
}
公共作废流程(Iterable Iterable)
{
准迭代器接口qit=ParallelIteratorWrapper.iterate(iterable);
对于(int i=0;i
我的问题是:

  • 直接使用
    迭代器是没有意义的,因为hasNext()和next()有一个同步问题,如果有人在您之前调用next(),hasNext()就没用了

  • 我很想使用,但我需要的唯一方法是
    poll()

  • 我想使用ConcurrentLinkedQueue来保存我的大量元素。。。但是我可能需要多次遍历元素,所以我不能使用它


有什么建议吗?

有一个调度程序线程,它在Iterable上迭代,并将元素调度到多个工作线程,这些工作线程对元素执行工作。您可以使用
ThreadPoolExecutor
自动执行此操作。

使用
poll()
方法或等效方法(例如番石榴)创建自己的
Producer
接口。实现选项很多,但是如果您有一个不可变的随机访问列表,那么您可以简单地维护一个线程安全的单调计数器(例如AtomicInteger)和调用列表。get(int)例如:

类ListSupplier实现供应商{
private final AtomicInteger next=新的AtomicInteger();
私有最终列表元素;//
…
公共获取(){
//由于边界检查,real impl更加复杂
//筋疲力尽时该怎么办
返回元素.get(next.getAndIncrement());
}
}

这是线程安全的,但您可能希望返回选项样式的内容,或者在耗尽时返回null。

在希望对数据进行第二次传递的场景中,迭代的顺序是否需要与第一遍相同?除了课程锁定和许多列表实现的
null
是一个有效条目之外,还有什么问题吗?@ChrisH:是的,顺序应该始终相同。@Tim:你是说我应该只使用
Iterator
吗?@Jason S,否,因为
Iterator
实现不能保证线程安全,而且从我在
AbstractList
中看到的实现肯定不是线程安全的。我只是问,问题是什么?谢谢,但我不想把工作调度机制(这很复杂,有一定的限制,原因超出了这个问题的范围)和控制共享元素访问的机制结合起来。
class ListSupplier<T> implements Supplier<T> {
  private final AtomicInteger next = new AtomicInteger();
  private final List<T> elements; // ctor injected

  …
  public <T> get() {
    // real impl more complicated due to bounds checks
    // and what to do when exhausted
    return elements.get(next.getAndIncrement());
  }
}