CopyOnWriteArrayList源码分析
来源:互联网 发布:淘宝优惠助手 编辑:程序博客网 时间:2024/05/19 06:14
CopyOnWriteArrayList
源码基于1.8.0_112
CopyOnWriteArrayList也是通过数组来存储元素,阅读过之前的ArrayList的话这边应该很容易理解
原理 :CopyOnWriteArrayList内部通过数组来存储数据,每次修改list都会产生一个新的数组,然后复制原始数据。修改方法都通过内部的而一个锁对象来实现同步。如果一个线程修改操作进行了一半,另外一个线程来读取集合,则它读取的是修改前的数组,不会产生同步异常。CopyOnWriteArrayList进行迭代遍历的时候,会保存一份快照,然后对这份快照进行遍历,这种机制称为安全失败(fail-safe)。
成员变量
大致浏览,结合具体方法来了解具体含义
// 锁对象 final transient ReentrantLock lock = new ReentrantLock(); // 存储数据的数组,只提供给get和set方法访问 private transient volatile Object[] array;
构造方法
先阅读默认构造函数,其他构造函数可在阅读完具体操作后再回来阅读
/** * 创建一个空的集合 */ public MyCopyOnWriteArrayList() { // 设置一个空数组 setArray(new Object[0]); } // 设置数组 final void setArray(Object[] a) { array = a; }
add(E e)
每次加入数据都会新建一个数组,性能较差
加入数据时会新建一个原本数组长度+1的数组,然后复制到新数组中,最后在末尾赋值
代码
/** * 添加对象 */ public boolean add(E e) { // 成员锁对象,和synchronized具有相同的功能,ReentrantLock的功能更加的丰富 final ReentrantLock lock = this.lock; // 加锁,每次只有一个线程可进入临界区 lock.lock(); try { // 拿到存储对象的数组 Object[] elements = getArray(); int len = elements.length; // 把原来的的数组复制到一个比原本长度大1位的数组中 // 如:A,B,C,D,E ---> A,B,C,D,E,NULL Object[] newElements = Arrays.copyOf(elements, len + 1); // 加入新的值 // 如:A,B,C,D,E,NULL ---> A,B,C,D,E,F newElements[len] = e; // 设置数组 setArray(newElements); return true; } finally { // 最后解锁 lock.unlock(); } } // 设置数组 final void setArray(Object[] a) { array = a; } // 获取数组 final Object[] getArray() { return array; }
get(int index)
很简单的方法,不解释
代码
/** * 随机访问 */ public E get(int index) { return get(getArray(), index); } @SuppressWarnings("unchecked") private E get(Object[] a, int index) { return (E) a[index]; }
remove(int index)
把不需要删除的数据复制到一个新的数组中
图解
代码
/** * 删除元素 */ public E remove(int index) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; E oldValue = get(elements, index); int numMoved = len - index - 1; // 移除的是最后一个元素 // 如:A,B,C,D,E ---> A,B,C,D if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1)); else { // 移除的不是最后一个元素 // 新建数组 Object[] newElements = new Object[len - 1]; // 复制前一段 System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index + 1, newElements, index, numMoved); // 设置数组 setArray(newElements); } // 返回移除的值 return oldValue; } finally { lock.unlock(); } }
iterator()
简单分析iterator
迭代访问的是原始数据的一份快照
// 对快照进行遍历 public COWIterator<E> iterator() { return new MyCopyOnWriteArrayList.COWIterator<E>(getArray(), 0); } static final class COWIterator<E> { // 快照 private final Object[] snapshot; /** Index of element to be returned by subsequent call to next. */ private int cursor; private COWIterator(Object[] elements, int initialCursor) { cursor = initialCursor; // 新建迭代器的时候保存一份快照 snapshot = elements; } public boolean hasNext() { return cursor < snapshot.length; } @SuppressWarnings("unchecked") public E next() { if (! hasNext()) throw new NoSuchElementException(); // 对快照进行访问 return (E) snapshot[cursor++]; } }
总结
- CopyOnWriteArrayList为线程安全的集合类
- 随机访问不需要同步,所以访问速度很快
- 修改操作会拷贝数组,性能很差
- 适合频繁访问,极少修改的情况下使用
0 0
- CopyOnWriteArrayList 源码分析
- Java CopyOnWriteArrayList 源码分析
- CopyOnWriteArrayList 源码分析
- CopyOnWriteArrayList源码原理分析
- CopyOnWriteArrayList源码分析
- 源码分析-CopyOnWriteArrayList
- CopyOnWriteArrayList源码分析
- CopyOnWriteArrayList-源码分析
- CopyOnWriteArrayList源码分析
- LinkedList&CopyOnWriteArrayList源码分析
- CopyOnWriteArrayList 源码阅读与分析
- jdk源码分析之CopyOnWriteArrayList
- 《Java源码分析》:CopyOnWriteArrayList/ CopyOnWriteArraySet
- CopyOnWriteArrayList 并发集合源码分析
- 《Java源码分析》:CopyOnWriteArrayList/ CopyOnWriteArraySet
- jdk并发包 CopyOnWriteArrayList源码分析
- JUC源码分析24-队列-CopyOnWriteArrayList,CopyOnWriteArraySet
- 【Java8源码分析】并发包-CopyOnWriteArrayList
- linux安装mysql后关机的时候经常死机
- Android编译运行项目时报错java.io.IOException: Please correct the above warnings first.
- 静态代码扫描(五)——Java资源关闭的特殊场景
- C#获取汉字拼音或首字母
- Strategy Pattern
- CopyOnWriteArrayList源码分析
- OpenCV常用函数记载
- 字符串——正则表达式匹配
- 织梦自增函数[field:global name=autoindex/]的用法
- Ogre : How to actually get morph animations to work in the engine
- Android ActivityThread(主线程或UI线程)简介
- [BZOJ2084]Antisymmetry(二分+hash)
- 数据库索引详解
- dedecms安装教程:留言本添加用户留言时间教程