我正在增强现有算法,该算法由多个独立步骤组成,以使用并发任务。每个任务都将创建多个对象来保存其结果。最后,我想列出从控制方法返回的所有结果。目前,我的代码看起来像那样
private final ExecutorService pool = ...;
// A single task to be performed concurrently with other tasks.
private class WorkHorse implements Callable<Void> {
private final Collection<X> collect;
public WorkHorse(Collection<X> collect, ...) {
this.collect = collect;
}
public Void call() {
for (...) {
// do work
synchronized (this.collect) {
this.collect.add(result);
}
}
return null;
}
}
// Uses multiple concurrent tasks to compute its result list.
public Collection<X> getResults() {
// this list is supposed to hold the results
final Collection<X> collect = new LinkedList<X>();
final List<WorkHorse> tasks = Arrays.asList(
new WorkHorse(collect, ...), new WorkHorse(collect, ...), ...);
this.pool.invokeAll(tasks);
// ## A ##
synchronized (collect) {
return collect;
}
}
我是否真的需要{#1}}“## A ##”来强制执行与工作任务中的修改操作之前发生的关系?或者我可以依赖所有写操作在synchronized
返回后发生并且对控制线程可见吗?有什么理由,为什么我不应该从自己的invokeAll
块中返回结果集合?
答案 0 :(得分:3)
不,你不需要那个。 invokeAll的文档指出,所有工作都应在返回时完成。所以当你到达return语句时,不应该有进一步的访问权。
答案 1 :(得分:0)
如果您有第二个synchronized
,则不需要第二个invokeAll()
。正如Zed所说,add()
将阻止所有任务完成。同时,synchronized
周围的同步将确保对集合的更改对所有线程都可见,包括原始调用线程。
至于你是否需要第一个(你没有问过) - 我试图删除两个LinkedList
块并且实际上无法让它失败,但是它可能是更安全的赌注。根据{{1}}的javadoc:
如果多个线程访问a LinkedList同时发生,至少是 其中一个线程修改了列表 在结构上,必须 外部同步。
其他“第二代”Collection
实施也有类似的警告。
请注意,对集合本身进行同步并没有什么神奇之处。您可以在外部类中声明一个单独的互斥锁(任何旧的Object
都可以),或者在外部类实例上进行同步,这也可以正常工作,只要所有WorkHorse
同步同样的事情。