CopyOnWriteArrayList 源码---JDK1.8
Posted emoji-emoji
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CopyOnWriteArrayList 源码---JDK1.8相关的知识,希望对你有一定的参考价值。
CopyOnWriteArrayList:通过copy一份以前元素的快照,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器"。该集合适合读多写少的场景(读没有加锁,其他更新操作均有加锁)。
/** The lock protecting all mutators */ final transient ReentrantLock lock = new ReentrantLock(); /** The array, accessed only via getArray/setArray. */ //volatile修饰,如果数组发生改变其他线程可见 private transient volatile Object[] array;
元素添加,上锁,线程安全的,每次只允许一个线程对该集合修改。
//添加元素到列表尾部 public boolean add(E e) { final ReentrantLock lock = this.lock; //上锁 lock.lock(); try { //获取数组的快照 Object[] elements = getArray(); //原数组长度 int len = elements.length; //每次增加元素的时候,都会进行数组copy Object[] newElements = Arrays.copyOf(elements, len + 1); //将新元素保存到数组中 newElements[len] = e; //更新原数组 setArray(newElements); return true; } finally { lock.unlock(); } }
在指定位置上添加元素:
//在指定位置上添加元素,支持重复元素 public void add(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (index > len || index < 0) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+len); Object[] newElements; //计算出旧数组需要移动的元素数量 int numMoved = len - index; //如果为0,说明要添加的位置是尾部 if (numMoved == 0) //直接len+1,copy newElements = Arrays.copyOf(elements, len + 1); else { //创建一个新数组,长度len+1 newElements = new Object[len + 1]; //copy,0--->index System.arraycopy(elements, 0, newElements, 0, index); //copy,index+1--->end System.arraycopy(elements, index, newElements, index + 1, numMoved); } newElements[index] = element; setArray(newElements); } finally { lock.unlock(); } }
更新指定位置上的元素:
//添加元素到指定位置,如果指定位置存在相同元素,什么也不做 public E set(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); E oldValue = get(elements, index); //要插入的元素和旧元素不一样 if (oldValue != element) { int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len); //更新以前位置上的元素 newElements[index] = element; setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue; } finally { lock.unlock(); } }
获取指定位置上的元素:
//获取指定位置上的元素 public E get(int index) { return get(getArray(), index); } //获取指定位置元素 private E get(Object[] a, int index) { return (E) a[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; //为0,说明移除的是尾部元素 if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1)); //不为0,需要将将index前后2部分数组分别copy else { Object[] newElements = new Object[len - 1]; //copy 0--index System.arraycopy(elements, 0, newElements, 0, index); //copy index+1--->end System.arraycopy(elements, index + 1, newElements, index, numMoved); //更新数组 setArray(newElements); } return oldValue; } finally { lock.unlock(); } }
以上是关于CopyOnWriteArrayList 源码---JDK1.8的主要内容,如果未能解决你的问题,请参考以下文章
Java并发编程之CopyOnWriteArrayList源码分析
「源码分析」CopyOnWriteArrayList 中的隐藏知识,你Get了吗?
死磕 java集合之CopyOnWriteArrayList源码分析