java.util.concurrent.CopyOnWriteArrayList
2013-04-15 16:56
323 查看
CopyOnWriteArrayList
CopyOnWriteArrayList是一个线程安全、并且在读操作时无锁的ArrayList。
1)添加
add(E e)
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1);//复制数组 newElements[len] = e;//添加到末尾 setArray(newElements); return true; } finally { lock.unlock(); } }
这里同样没有使用synchronized关键字,而是使用ReentrantLock。
和ArrayList不同的是,这里每次都会创建一个新的object数组,大小比之前数组大1。将之前的数组复制到新数组,并将新加入的元素加到数组末尾。
2)删除
remove(Object o)
public boolean remove(Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (len != 0) { // Copy while searching for element to remove // This wins in the normal case of element being present int newlen = len - 1; Object[] newElements = new Object[newlen];//新建数组 for (int i = 0; i < newlen; ++i) { if (eq(o, elements[i])) { // found one; copy remaining and exit for (int k = i + 1; k < len; ++k) newElements[k-1] = elements[k]; setArray(newElements); return true; } else newElements[i] = elements[i]; } // special handling for last cell if (eq(o, elements[newlen])) { setArray(newElements); return true; } } return false; } finally { lock.unlock(); } }
此方法为什么这么直接进行数组的复制呢?为何不适用system的arrayCopy来完成?
3)获取
get(int index)
public E get(int index) { return (E)(getArray()[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 CopyOnWriteArraySet
- java.util.concurrent.CopyOnWriteArrayList
- java.util.concurrent 之CopyOnWriteArrayList
- 《java.util.concurrent 包源码阅读》08 CopyOnWriteArrayList和CopyOnWriteArraySet
- Java:concurrent包下面的Collection接口框架图( CopyOnWriteArraySet, CopyOnWriteArrayList,ConcurrentLinkedQueue,BlockingQueue)
- java.util中ArralyList 与 CopyOnWriteArrayList
- Java concurrent Framework并发容器之CopyOnWriteArrayList(1.6)源码分析
- Java中 CopyOnWriteArrayList 的使用与ConcurrentModificationException错误的避免
- JAVA提高二十:CopyOnWriteArrayList&CopyOnWriteArraySet&ConcurrentHashMap介绍
- Java线程集合类ConcurrentHashMap&CopyOnWriteArrayList 深入
- java.util.concurrent.CopyOnWriteArraySet
- Java Concurrent --CopyOnWriteArrayList
- Java并发容器之CopyOnWriteArrayList(转载)
- Java中 CopyOnWriteArrayList 的使用
- Java并发编程:并发容器之CopyOnWriteArrayList
- Java CopyOnWriteArrayList工作原理及实现(一)
- Java多线程工具包java.util.concurrent---ReadWriteLock
- Java 集合 List CopyOnWriteArrayList
- java并发之CopyOnWriteArrayList
- 从ArrayList中删除对象报java.util.ConcurrentModificationException异常解决