我有一个包含大量元素的不可变Iterable<X>
。 (它恰好是List<>
,但没关系。)
我想要做的是启动一些并行/异步任务来使用相同的迭代器迭代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 */
}
这是我的问题:
直接使用Iterator
是没有意义的,因为hasNext()和next()有同步问题,如果别人在你做之前调用next(),那么hasNext()是无用的
我很乐意使用Queue
,但我唯一需要的方法是poll()
我喜欢使用ConcurrentLinkedQueue来保存我的大量元素......除了我可能不得不多次遍历这些元素,所以我不能使用它。
有什么建议吗?
答案 0 :(得分:1)
使用Producer
方法或等效方法创建自己的poll()
接口(例如,Guava的Supplier
)。实现选项很多但是如果你有一个不可变的随机访问列表,那么你可以简单地维护一个线程安全的单调计数器(例如AtomicInteger)并调用list.get(int)例如:
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());
}
}
这是线程安全的,但你可能想要返回一个Option风格的东西,或者在用尽时返回null。
答案 1 :(得分:0)
让一个调度程序线程迭代Iterable,并将元素分派给执行元素工作的多个工作线程。您可以使用ThreadPoolExecutor
自动执行此操作。