3

我有一组预先填充的字符串。我想迭代项目,在迭代时,我需要“做工作”,这也可能从集合中删除项目。我想为每个项目的“工作”产生一个新线程。请注意,在“做工作”期间,只有一些项目会从集合中移除。

现在我有以下问题,

我可以通过简单地使用 Collections.synchronizedSet(new HashSet()); 来实现这一点吗?? 我猜这会抛出 ConcurrentModificationException 因为我在迭代时从列表中删除项目。如何在没有一致性问题的情况下有效地实现上述行为?

谢谢!

4

4 回答 4

4

我会使用 ExecutorService

ExecutorService es = Executors.newFixedThreadPool(n);
List<Future<String>> toRemove = new ARraysList<>();
for(String s: set)
   toRemove.add(es.submit(new Task(s)));
for(Future<String> future : toRemove()) {
   String s = future.get();
   if (s != null)
       set.remove(s);
}

这避免了需要以多线程方式访问集合。

于 2012-07-23T08:53:43.707 回答
1

是的,SynchronisedSet 仍然会抛出 ConcurrentModificationExceptions。

尝试这个:

Set s = Collections.newSetFromMap(new ConcurrentHashMap())

当多个线程访问和修改它时,ConcurrentHashMap 绝不应该抛出 ConcurrentModificationException。

于 2012-07-23T09:09:18.070 回答
1

使用一个主生产者线程,该线程将从集合中删除元素并将它们提供给消费者线程。消费者线程无需“亲自”删除项目。

于 2012-07-23T08:51:50.607 回答
0

该方法取决于您集合中的数据与操作的成功完成之间的关系。

Remove from Set 独立于任务执行的结果

如果您不关心线程执行的实际结果,则可以在分派任务时遍历集合并删除每个项目(您已经有一些示例)

仅当任务执行成功完成时从 Set 中移除

如果从集合中删除对执行成功是事务性的,则可以使用Futures 收集有关任务执行成功的信息。这样,只有成功执行的项目才会从原始集合中删除。无需同时访问 Set 结构,因为您可以使用Futures 和 an将执行与检查分开ExecutorService。例如:

// This task will execute the job and, 
// if successful, return the string used as context
class Task implements Callable<String> {
    final String target;
    Task(String s) {
        this.target = s; 
    }
    @Override
    public String call() throws Exception {
        // do your stuff
        // throw an exception if failed 
        return target;
    }
}

这就是它的使用方式:

ExecutorService executor;

Set<Callable<String>> myTasks = new HashSet<Callable<String>>();
for(String s: set) {
   myTasks.add(new Task(s));
}
List<Future<String>> results = executor.invoqueAll(myTasks);
for (Future<String> result:results) {
    try {
        set.remove(result.get());
    } catch (ExecutionException ee) {
        // the task failed during execution - handle as required
    } catch (CancellationException ce) {
        // the task was cancelled - handle as required
    }
}
于 2012-07-23T10:13:10.917 回答