代码之家  ›  专栏  ›  技术社区  ›  janko

我是否需要对invokeAll调用的结果进行同步?

  •  4
  • janko  · 技术社区  · 16 年前

    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;
        }
    }
    

    我真的需要这个吗 synchronized 在“#####”执行与辅助任务中的修改操作的“发生在之前”关系?或者,我可以依赖于之后发生的所有写入操作吗 invokeAll 返回并对控制线程可见吗?还有什么原因,为什么我不应该从它自己的内部返回结果集合

    2 回复  |  直到 16 年前
        1
  •  3
  •   Zed    16 年前

    不,你不需要那个。文件 invokeAll 声明所有作业应在其返回时完成。因此,当您到达return语句时,应该没有进一步的collect访问权限。

        2
  •  0
  •   David Moles paddy-p    16 年前

    你不需要第二个 synchronized 如果你有第一个在那里。正如泽德所说, invokeAll() 将阻止,直到所有任务完成。同时,同步也在进行 add() 将确保对集合的更改对所有线程都可见,包括原始调用线程。

    至于你是否需要 一个(你没有问过)——我试着把两个都去掉了 LinkedList :

    如果多个线程访问一个 其中一个线程修改列表 在结构上,它 必须 是 外部同步。

    另一个“第二代” Collection

    顺便注意,在集合本身上进行同步并没有什么神奇之处。您可以声明一个单独的互斥体(任何旧互斥体) Object WorkHorse