如果不能保证对迭代器的同步访问,我们为什么要使用同步集合?

Why do we use synchronized collection if it doesn't guarantee the synchronized access on iterators?

例如,在下面的代码中,我们必须在进行迭代时将列表包装在同步块中。 Collections.synchronizedList 是否使列表同步?如果它不提供任何便利,我们为什么要这样做?谢谢!

List<Integer> list = Collections.synchronizedList( new ArrayList<>(Arrays.asList(4,3,52)));

synchronized(list) { 
      for(int data: list)
         System.out.print(data+" "); 
}

https://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html

The reason is that iteration is accomplished via multiple calls into the collection, which must be composed into a single atomic operation.

另见 https://www.baeldung.com/java-synchronized-collections

Wrapper 用于同步添加和删除包装集合中的元素。

JavaDoc 提到迭代不同步,您需要自己同步它。

 * It is imperative that the user manually synchronize on the returned
 * list when iterating over it

但是其他访问操作是线程安全的并且也建立了happens before关系(因为它们使用synchronized)。

Why do we do this if it doesn't provide any convenience

它在迭代时没有帮助你不等于没有提供便利。

所有方法 - getsizesetisEmpty 等 - 都是同步的。这意味着它们可以看到在任何线程中进行的所有写入。

如果没有同步,就无法保证一个线程中所做的更新对任何其他线程都是可见的,因此一个线程可能看到大小为 5 而另一个线程看到大小为 6,例如。

使列表同步的机制是使其所有方法synchronized:这实际上意味着方法的主体被包裹在synchronized (this) { ... }块中。

iterator() 方法仍然如此:synchronized 也是如此。但是 synchronized 块在 iterator() returns 时完成,而不是在您完成迭代时完成。这是语言设计方式的基本限制。

所以你必须自己添加同步块来帮助语言。

Collections.synchronizedList 方法同步 addremove 等方法。但是,它不同步 iterator() 方法。考虑以下场景:

  • 线程 1 正在遍历列表
  • 线程 2 正在向其中添加一个元素

在这种情况下,您将获得 ConcurrentModificationException,因此,必须同步对 iterator() 方法的调用。