为什么当我们已经有矢量时需要同步ArrayList?

我们什么时候使用同步的ArrayList ? 我们已经有了同步的Vector


我认为你有这个错误。 ArrayList是非同步的,Vector是。

同步意味着每个操作都是线程安全的 - 如果您同时使用来自两个线程的相同向量,则它们不会破坏状态。 但是,这会让它变慢。

如果您正在单线程环境中工作(或者列表仅限于线程并且从不共享),请使用ArrayList。 如果您正在使用共享相同集合的多个线程,请使用Vector或使用ArrayList,但以其他方式同步(例如,手动或通过包装器)。


ArrayList不通过http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html进行同步


ArrayList不是开箱即用的。

List接口的可调整大小数组实现。 实现所有可选的列表操作,并允许所有元素,包括null。 除了实现List接口之外,该类还提供了一些方法来控制用于内部存储列表的数组大小。 (这个类大致相当于Vector,除了它是不同步的。)

这可以避免在您知道您不需要线程安全的情况下(例如完全封装的私有数据)的一些性能问题。 然而,当使用迭代器覆盖它们时,ArrayList和Vector都有问题:迭代通过任一类型的集合时,如果添加或删除数据,则会引发ConcurrentModificationException:

请注意,此实现不同步。 如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则它必须在外部同步。 (结构修改是任何添加或删除一个或多个元素的操作,或明确调整后备数组的大小;仅设置元素的值不是结构修改。)这通常通过同步某些自然封装名单。 如果不存在这样的对象,则应使用Collections.synchronizedList方法“列出”列表。 这最好在创建时完成,以防止意外的不同步访问列表:

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

这个类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在迭代器创建后的任何时候,结构上都会修改列表,除了通过迭代器自己的remove或add方法以外,迭代器将抛出ConcurrentModificationException。 因此,面对并发修改,迭代器快速而干净地失败,而不是在将来某个未确定的时间冒着任意的,非确定性的行为风险。

请注意,迭代器的故障快速行为无法得到保证,因为一般来说,在存在非同步并发修改的情况下不可能做出任何硬性保证。 失败快速迭代器尽最大努力抛出ConcurrentModificationException。 因此,编写一个依赖于此异常的程序是正确的:迭代器的快速失败行为应仅用于检测错误。

ArrayList有各种有用的风格,但是,Vector不是。 我个人最喜欢的是CopyOnWriteArrayList:

ArrayList的线程安全变体,其中所有可变操作(add,set等)都通过创建底层数组的新副本来实现。

这通常代价太高,但当遍历操作的数量远远超过突变时,可能会比替代方法更有效,而且当您不能或不想同步遍历时,它很有用,但需要排除并发线程之间的干扰。 “快照”样式迭代器方法在创建迭代器时使用对数组状态的引用。 这个数组在迭代器的生命周期中永远不会改变,所以干扰是不可能的,迭代器保证不抛出ConcurrentModificationException。 自迭代器创建以来,迭代器不会反映添加,删除或对列表的更改。 迭代器本身的元素更改操作(删除,设置和添加)不受支持。 这些方法抛出UnsupportedOperationException。

CopyOnWriteArrayLists在GUI工作中非常有用,特别是在显示更新数据集的情况下(例如,在屏幕上移动图标)。 如果您可以容忍让您显示的数据列表过期一帧(因为您的生产者线程稍微落后于图形更新线程),CopyOnWriteArrayLists是完美的数据结构。

链接地址: http://www.djcxy.com/p/76105.html

上一篇: Why do we need synchronized ArrayLists when we already have Vectors?

下一篇: Should Java treat arrays as objects?