我有一个填充了' someObject'的ArrayList。我需要迭代这个列表,有4个不同的线程(使用Futures& Callables)。线程将保留它遇到的前5个有价值的对象。我首先尝试创建一个并行流,但这并没有很好地解决。是否有一些我没想到的显而易见的事情,所以每个线程都可以迭代对象,而不是两次抓取同一个对象?
答案 0 :(得分:1)
您可以使用AtomicInteger来遍历列表:
class MyRunnable implements Runnable {
final List<SomeObject> list;
final AtomicInteger counter; // initialize to 0
public void run() {
while(true) {
int index = counter.getAndIncrement();
if(index < list.size()) {
do something with list.get(index);
} else {
return;
}
}
}
}
只要每个MyRunnable
具有相同的AtomicInteger
引用,它们就不会重复索引
答案 1 :(得分:1)
您不需要AtomicInteger
或任何其他同步。
您应该根据处理线程的数量(其编号也是预先知道的)在逻辑上对列表进行逻辑分区(其大小是预先知道的),并让它们中的每一个都在其自己的[from,to]部分上运行。列表。
这完全不需要任何同步(即使它只是一个优化的同步,如class Worker<T> implements Runnable {
final List<T> toProcess;
protected Worker(List<T> list, int fromInc, int toExcl){
// note this does not allow passing an empty list or specifying an empty work section but you can relax that if you wish
// this also implicitly checks the list for null
Preconditions.checkArgument(fromInc >= 0 && fromInc < list.size());
Preconditions.checkArgument(toExcl > 0 && fromInc <= list.size());
// note: this does not create a copy, but only a view so it's very cheap
toProcess = list.subList(fromInc, toExcl);
}
@Override
public final void run() {
for(final T t : toProcess) {
process(t);
}
}
protected abstract process(T t);
}
),这是你应该一直努力的目标(只要它是安全的)。
伪代码
AtomicInteger
与<!--<resources>-->
<!--<resource>-->
<!--<directory>src/main/resources</directory>-->
<!--<includes>-->
<!--<include>*</include>-->
<!--</includes>-->
<!--<filtering>true</filtering>-->
<!--</resource>-->
<!--</resources>-->
解决方案(实际上任何不涉及复制列表的解决方案)一样,此解决方案还假设一旦您将列表移除,不将修改列表每个线程和处理已经开始。在处理过程中修改列表将导致未定义的行为。