当synchronizedList()或Vector已经同步时,为什么还需要外部同步?

Son*_*ngo 2 java multithreading synchronization arraylist thread-safety

ArrayList未同步.但是有一种方法可以获得java.util.ArrayListJavaDoc中提到的同步方法:

List list = Collections.synchronizedList(new ArrayList(...));
Run Code Online (Sandbox Code Playgroud)

java.util.CollectionsJavaDoc中,您可以读到" 当迭代它时,用户必须在返回的列表上手动同步: "

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

使用同步的ArrayList会产生额外的工作,为什么不使用 java.util.Vector?使用这种方法有优势吗?

我在http://www.coderanch.com/上找到了这个问题,我在同一篇文章中分享了它的好答案.

Gra*_*ray 7

在java.util.Collections JavaDoc中,您可以读到"当迭代它时,用户必须在返回的列表上手动同步:"

如果您在列表上执行多个事务(例如迭代它),那么同步列表将无法保护您免受攻击ConcurrentModificationException.当你在迭代它时会有人添加或删除到列表,这将会抛出.

Collections.synchronizedList()防止从多个线程并发操作的列表.在迭代器的情况下,您正在进行列表调用,然后返回到您的代码,然后再次进行列表调用.即使这些方法是同步的,在此期间也不会对列表中运行的其他线程的竞争条件进行保护.

使用synchronized ArrayList会产生额外的工作,为什么不使用java.util.Vector呢?使用这种方法有优势吗?

Vector在这里没有帮助.它也会在同样的情况下抛出异常.引用javadocs:

Vector的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建Iterator之后的任何时候对Vector进行结构修改,除了通过Iterator自己的remove或add方法之外,Iterator将抛出ConcurrentModificationException.

而且,这Vector是一个非常古老的课程.人们普遍认为使用同步更好ArrayList.

以下是您可以做的几件事:

  • 您可以将列表复制到另一个集合中,然后可以迭代.即使其他线程在同步列表中添加或删除,您的本地集合也是安全的.这并不能保护您免受对列表中元素的修改.
  • 您可以切换到完全并发的集合,例如ConcurrentHashMap(当然不是列表),在迭代时处理对集合的修改. ConcurrentSkipList或者LinkedBlockingQueue是其他选择.
  • 正如@Geek指出的那样,CopyOnWriteArrayList是另一种选择,尽管性能很大程度上依赖于迭代和写入的比率.