Java技术——CopyOnWriteArrayList源码解析
来源:互联网 发布:浮云网淘宝小号专卖 编辑:程序博客网 时间:2024/06/06 00:55
0. 前言
CopyOnWriteArrayList是一个线程安全,读操作时无锁,但是写操作有锁的ArrayList。是读写分离思想的体现。
实现原理是当某个线程要修改List中的元素时,会把列表中的元素Copy一份,然后在新数组中对元素进行修改,最后把新元素赋值给原来的List的。这样就可以实现读操作不需要加锁。
JDK1.5开始Java并发包提供了CopyOnWriteArrayList和CopyOnWriteArraySet。这种机制的核心就是使读写分离,使并发场景下以读为主的操作性能更高,但显然占用的空间翻了一倍,是一种空间换时间的策略。
1. CopyOnWriteArrayList源码
1.1 CopyOnWriteArrayList初始化
从下面源码中可以看出CopyOnWriteArrayList会创建一个元素数为0的数组,而ArrayList中则是默认为10。
底层数据结构array对象数组很明显被volatile关键字修饰,保证内存可见性。
//创建方法List<String> list = new CopyOnWriteArrayList<String>();//相关源码//底层数据结构private volatile transient Object[] array; final Object[] getArray() { return array;}final void setArray(Object[] a) { array = a;}//创建了一个个数为0的数组public CopyOnWriteArrayList() { setArray(new Object[0]);}
1.2 CopyOnWriteArrayList的add操作
public boolean add(E e) { finalReentrantLock lock = this.lock; lock.lock();//上锁 try { Object[]elements = getArray();//获取当前的数组 intlen = elements.length; Object[]newElements = Arrays.copyOf(elements, len + 1); newElements[len]= e;//将新元素置于新数组的末尾 setArray(newElements);//将newElements设置为全局array returntrue; }finally { lock.unlock();//解锁 }}
根据以上代码可知,CopyOnWriteArrayList每增加一个新元素,都要进行一次数组的复制消耗,所以是一种空间换时间的策略,而且add操作进行了加锁(否则多线程下写操作会出错),并且是对新的数组进行修改,remove操作也一样。所以在多线程操作时不会出现java.util.ConcurrentModificationException错误。
1.3 CopyOnWriteArrayList的get操作
public E get(int index) { return(E) (getArray()[index]);}
从源码可以看出,CopyOnWriteArrayList的读操作没有上锁。因为array数组是volatile修饰的,也就是当你对volatile进行写操作后,会将写过后的array数组强制刷新到主内存,从而在读操作getArray()时会强制从主内存将array读出来。
1.4 CopyOnWriteArrayList的remove操作
public boolean remove(Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray();//获取原数组 int len = elements.length;//获取原数组长度 if (len != 0) { int newlen = len - 1;//新数组长度为原数组长度-1 Object[] newElements = new Object[newlen];//创建新数组 for (int i = 0; i < newlen; ++i) {//遍历新数组 if (eq(o, elements[i])) { // 将旧数组中将被删除元素之后的元素复制到新数组中 for (int k = i + 1; k< len; ++k) newElements[k - 1]= elements[k]; setArray(newElements);//将新数组赋给全局array return true; } else newElements[i] =elements[i];//将旧数组中将被删除元素之前的元素复制到新数组中 } if (eq(o, elements[newlen])) {//将要删除的元素时旧数组中的最后一个元素 setArray(newElements); return true; } } return false; }finally { lock.unlock(); }}
大致流程是上锁后,新建一个比原数组长度-1的新数组,遍历旧数组把除了要删除元素的其他所有元素赋值到新数组中。最后将这个新数组设置给原来的array。这里有个小的点,ArrayList的remove使用了System.arraycopy,而这里却没有使用这个方法,所以理论上这里的remove的性能要比ArrayList低。
2 CopyOnWriteArrayList和ArrayList的区别
(1)CopyOnWriteArrayList线程安全,写有锁读无锁,适合多线程中读操作较多的场景。而ArrayList不是线程安全,不能应用在多线程场景中。
(2)CopyOnWriteArrayList底层数据结构是一个Object[],初始容量为0,每增加一个元素容量加1,而ArrayList的初始容量为10,扩容机制为1.5倍加1。
- Java技术——CopyOnWriteArrayList源码解析
- Java并发编程与技术内幕:CopyOnWriteArrayList、CopyOnWriteArraySet源码解析
- CopyOnWriteArrayList源码解析——JDK1.8
- CopyOnWriteArrayList源码解析
- CopyOnWriteArrayList源码解析
- Java CopyOnWriteArrayList 源码分析
- 【JDK】:CopyOnWriteArrayList、CopyOnWriteArraySet 源码解析
- 《Java源码分析》:CopyOnWriteArrayList/ CopyOnWriteArraySet
- 《Java源码分析》:CopyOnWriteArrayList/ CopyOnWriteArraySet
- JAVA多线程之——CopyOnWriteArrayList
- Java并发容器——CopyOnWriteArrayList
- JDK并发工具类源码学习系列——CopyOnWriteArrayList
- CopyOnWriteArrayList解析
- JDK源码解析之ArrayList与Vector与CopyOnWriteArrayList
- Java集合类总结5——CopyOnWriteArrayList
- java CopyOnWriteArrayList
- 【Java】CopyOnWriteArrayList
- Java concurrent Framework并发容器之CopyOnWriteArrayList(1.6)源码分析
- 4月16日,TestSecurity,每日20行。
- 前端面试题整理汇总(一)
- [AWDwR4]13章 Playtime1 的实现
- 文件操作之fgets()
- @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
- Java技术——CopyOnWriteArrayList源码解析
- shodan 收索网络摄像头
- 启动活动的最佳写法
- like查询时索引优化
- 最大化 Xcode Debug Console 窗口
- [AWDwR4]13章出错 protect_against_forgery
- Folding Gym
- UVA-12108
- 常用类