概述
CopyOnWriteArrayList
CopyOnWriteArrayList是一个线程安全、并且在读操作时无锁的ArrayList。
1)添加
add(E e)
这里同样没有使用synchronized关键字,而是使用ReentrantLock。
和ArrayList不同的是,这里每次都会创建一个新的object数组,大小比之前数组大1。将之前的数组复制到新数组,并将新加入的元素加到数组末尾。
2)删除
remove(Object o)
此方法为什么这么直接进行数组的复制呢?为何不适用system的arrayCopy来完成?
3)获取
get(int index)
这里有可能脏读。但是销量非常高。
//通过看集合包和并发包可以看出一些不同的编程思路。这里为什么就不事先做范围的检查?
从上可见,CopyOnWriteArrayList基于ReentrantLock保证了增加元素和删除元素动作的互斥。在读操作上没有任何锁,这样就保证了读的性能,带来的副作用是有时候可能会读取到脏数据。
既然这样的话,应用的场景在哪呢?知道的朋友请告诉我一下。
补充:
CopyOnWriteArrayList 和 CopyOnWriteArraySet
可以用两种方法创建线程安全支持数据的 List
-- Vector
或封装 ArrayList
和 Collections.synchronizedList()
。java.util.concurrent
包添加了名称繁琐的 CopyOnWriteArrayList
。为什么我们想要新的线程安全的 List
类?为什么 Vector
还不够?
最简单的答案是与迭代和并发修改之间的交互有关。使用 Vector
或使用同步的 List
封装器,返回的迭代器是 fail-fast 的,这意味着如果在迭代过程中任何其他线程修改 List,迭代可能失败。
Vector
的非常普遍的应用程序是存储通过组件注册的监听器的列表。当发生适合的事件时,该组件将在监听器的列表中迭代,调用每个监听器。为了防止 ConcurrentModificationException
,迭代线程必须复制列表或锁定列表,以便进行整体迭代,而这两种情况都需要大量的性能成本。
CopyOnWriteArrayList
类通过每次添加或删除元素时创建支持数组的新副本,避免了这个问题,但是进行中的迭代保持对创建迭代器时的当前副本进行操作。虽然复制也会有一些成本,但是在许多情况下,迭代要比修改多得多,在这些情况下,写入时复制要比其他备用方法具有更好的性能和并发性。
如果应用程序需要 Set
语义,而不是 List
,那么还有一个 Set
版本 -- CopyOnWriteArraySet
。
最后
以上就是俏皮楼房为你收集整理的java.util.concurrent.CopyOnWriteArrayList的全部内容,希望文章能够帮你解决java.util.concurrent.CopyOnWriteArrayList所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复