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

时间:2013-12-19 21:11:33

标签: java multithreading arraylist synchronization thread-safety

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

List list = Collections.synchronizedList(new ArrayList(...));

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

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

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

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

1 个答案:

答案 0 :(得分:7)

  

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

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

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

  

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

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

  

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

此外,Vector是一个非常古老的类。人们普遍认为最好使用同步ArrayList

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

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