Collections.synchronizedList和synchronized

rom*_*sky 65 java collections synchronization

List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
    list.add("message");
}
Run Code Online (Sandbox Code Playgroud)

块"synchronized(list){}"真的需要吗?

Sam*_*erg 94

您不需要像放入示例中那样进行同步.但是,非常重要的是,在迭代时需要在列表周围进行同步(如Javadoc中所述):

当迭代它时,用户必须手动同步返回的列表:

List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());   
}
Run Code Online (Sandbox Code Playgroud)

  • 链接到上述声明:[docs](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList(java.util.List)) (13认同)
  • 只要您知道在迭代时列表没有被更新,您就不需要同步它.不过,我不知道我是否会将该用例描述为"常见".(我已经看过很多次ConcurrentModificationException.)在你提到的用例中,当另一个线程迭代时,是什么阻止线程再次添加到列表中?当其他线程完成更新列表时,迭代线程如何"知道"? (3认同)
  • 像这样的同步集合的常见用例是在多个线程中添加到列表中,但仅在所有任务完成后才对其进行迭代。在这种情况下,我认为没有任何理由围绕迭代进行同步,因为它是从单个线程完成的。 (2认同)

NPE*_*NPE 28

这取决于synchronized块的确切内容:

  1. 如果块在列表上执行单个原子操作(如在您的示例中),则这synchronized是多余的.

  2. 如果该块执行列表上的多个操作- ,需要维持用于化合物操作的持续时间的锁定 -则synchronized多余的.一个常见的例子是迭代列表.


ass*_*ias 21

Collections.synchronizedList add方法的底层代码是:

public void add(int index, E element) {
    synchronized (mutex) {list.add(index, element);}
}
Run Code Online (Sandbox Code Playgroud)

因此,在您的示例中,不需要添加同步.

  • 互斥体是javadoc中记录的集合本身(this). (3认同)

小智 16

另外需要注意的是,任何使用迭代器的方法(例如Collections.sort())也需要封装在synchronized块中.


小智 7

阅读此Oracle Doc

它说"当迭代时,用户必须手动同步返回的列表"