CopyOnWriteArrayList源码
实现List、RandomAccess、Cloneable
List接口定义List集合的操作方法
RandomAccess实现此接口的类可以随机访问
Cloneable实现此接口的类可以进行拷贝操作
重要说明:
CopyOnWriteArrayList是线程安全的,
通过CopyOnWriteArrayList对象中修改方法进行加锁,保证集合的线程安全
同时对数组进行修改时,把当前对象的数组拷贝一份newElements,先对newElements进行操作,操作完再复制给对象的数组,减少对查询类操作的锁定
代码翻译:
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8673264195747942595L; 保护设置属性方法的锁 final transient ReentrantLock lock = new ReentrantLock(); 只能通过getArray/setArray访问的数组 private transient volatile Object[] array; 获得数组,不是私有方法所以可以从CopyOnWriteArraySet访问 final Object[] getArray() { return array; } 设置数组 final void setArray(Object[] a) { array = a; } 创建一个空数组 public CopyOnWriteArrayList() { setArray(new Object[0]); } 根据指定的集合创建一个包含所有元素的数组 主要方法是 Arrays.copyOf() public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements; if (c.getClass() == CopyOnWriteArrayList.class) elements = ((CopyOnWriteArrayList<?>)c).getArray(); else { elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); } setArray(elements); } 创建一个包含给定数组副本的列表。 public CopyOnWriteArrayList(E[] toCopyIn) { setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); } 返回数组大小 public int size() { return getArray().length; } 判断数组是否为空 public boolean isEmpty() { return size() == 0; } 判断o1与o2是否相等 private static boolean eq(Object o1, Object o2) { return (o1 == null) ? o2 == null : o1.equals(o2); } indexOf的静态版本,允许重复调用而不需要每次重新获得数组 private static int indexOf(Object o, Object[] elements, int index, int fence) { if (o == null) { for (int i = index; i < fence; i++) if (elements[i] == null) return i; } else { for (int i = index; i < fence; i++) if (o.equals(elements[i])) return i; } return -1; } lastIndexOf的静态版本 private static int lastIndexOf(Object o, Object[] elements, int index) { if (o == null) { for (int i = index; i >= 0; i--) if (elements[i] == null) return i; } else { for (int i = index; i >= 0; i--) if (o.equals(elements[i])) return i; } return -1; } 如果数组中包含指定元素,则返回true public boolean contains(Object o) { Object[] elements = getArray(); return indexOf(o, elements, 0, elements.length) >= 0; } 根据对象获得索引位置 public int indexOf(Object o) { Object[] elements = getArray(); return indexOf(o, elements, 0, elements.length); } 返回从index索引开始,对象E第一次出现的索引位置,如果没有返回-1 public int indexOf(E e, int index) { Object[] elements = getArray(); return indexOf(e, elements, index, elements.length); } 从后开始检索对象o第一次出现的位置 public int lastIndexOf(Object o) { Object[] elements = getArray(); return lastIndexOf(o, elements, elements.length - 1); } 返回从index索引反向开始,对象E第一次出现的索引位置,如果没有返回-1 public int lastIndexOf(E e, int index) { Object[] elements = getArray(); return lastIndexOf(e, elements, index); } 拷贝一个CopyOnWriteArrayList对象镜像,里面的数组不会被拷贝,原对象中数组与拷贝对象中数组存储在相同的堆 重点说明在方法中调用了clone.resetLock()方法,对ReentrantLock锁进行了重置 public Object clone() { try { @SuppressWarnings("unchecked") CopyOnWriteArrayList<E> clone = (CopyOnWriteArrayList<E>) super.clone(); clone.resetLock(); return clone; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } } 返回数组 public Object[] toArray() { Object[] elements = getArray(); return Arrays.copyOf(elements, elements.length); } 返回指定参数类型的数组对象, @SuppressWarnings("unchecked") public <T> T[] toArray(T a[]) { Object[] elements = getArray(); int len = elements.length; //如果T数组长度小于调用方数组长度,则在调用方数组中截取长度为T的新数组 if (a.length < len) return (T[]) Arrays.copyOf(elements, len, a.getClass()); else {//如果T数组长度大于等于调用方数组长度,则新分配一个数组 System.arraycopy(elements, 0, a, 0, len); if (a.length > len) a[len] = null; return a; } } 返回数组中指定索引的值 @SuppressWarnings("unchecked") private E get(Object[] a, int index) { return (E) a[index]; } 返回指定索引的值 public E get(int index) { return get(getArray(), index); } 把指定索引位置的元素值替换为element 重点说明: public E set(int index, E element) { final ReentrantLock lock = this.lock; //第一步先获得锁 lock.lock(); try { //定义临时数组变量 Object[] elements = getArray(); //从elements获得index索引的值,oldValue E oldValue = get(elements, index); //判断oldValue与newValue是否相等 //【if语句一定会执行,不会执行else】 //如果不相等,生成新的数组 if (oldValue != element) { int len = elements.length; /拷贝当前数组对象,重新分配内存创建新数组对象newElements Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; //将newElements重新复制给当前对象的数组变量 setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue; } finally { //释放锁 lock.unlock(); } } //添加对象e public boolean add(E e) { final ReentrantLock lock = this.lock; //第一步先获得锁 lock.lock(); try { //定义临时数组变量 Object[] elements = getArray(); int len = elements.length; //拷贝当前数组对象,重新分配内存创建新数组对象newElements Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { //释放锁 lock.unlock(); } } 在数组指定索引插入Element对象,如果index位置有值,则原有值向右移动 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; if (numMoved == 0) //拷贝当前数组对象,重新分配内存创建新数组对象newElements newElements = Arrays.copyOf(elements, len + 1); else { //使用System.arraycopy()方法进行数组间的拷贝 newElements = new Object[len + 1]; System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index, newElements, index + 1, numMoved); } newElements[index] = element; setArray(newElements); } finally { //释放锁 lock.unlock(); } } 删除指定index位置的数据 public E remove(int index) { final ReentrantLock lock = this.lock; //第一步先获得锁 lock.lock(); try { //定义临时数组变量 Object[] elements = getArray(); int len = elements.length; //获得oldValue E oldValue = get(elements, index); int numMoved = len - index - 1; //numMoved == 0代表index为数组最后一位 if (numMoved == 0) //拷贝当前数组对象,重新分配内存创建新数组对象 setArray(Arrays.copyOf(elements, len - 1)); else { //如果index为非数组最后一位,则新建一个长度减一的数组,通过System.arraycopy()方式进行拷贝 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(); } } 删除对象o第一次出现的数组 public boolean remove(Object o) { Object[] snapshot = getArray(); int index = indexOf(o, snapshot, 0, snapshot.length); return (index < 0) ? false : remove(o, snapshot, index); } 从snapshot数组中删除指定index位置的数据 private boolean remove(Object o, Object[] snapshot, int index) { final ReentrantLock lock = this.lock; //第一步先获得锁 lock.lock(); try { //定义临时数组变量 Object[] current = getArray(); int len = current.length; if (snapshot != current) findIndex: { int prefix = Math.min(index, len); for (int i = 0; i < prefix; i++) { if (current[i] != snapshot[i] && eq(o, current[i])) { index = i; break findIndex; } } if (index >= len) return false; if (current[index] == o) break findIndex; index = indexOf(o, current, index, len); if (index < 0) return false; } Object[] newElements = new Object[len - 1]; System.arraycopy(current, 0, newElements, 0, index); System.arraycopy(current, index + 1, newElements, index, len - index - 1); setArray(newElements); return true; } finally { lock.unlock(); } } 如果对象e不存在,则添加对象e public boolean addIfAbsent(E e) { Object[] snapshot = getArray(); return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false : addIfAbsent(e, snapshot); } 在snapshot数组中添加对象e private boolean addIfAbsent(E e, Object[] snapshot) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] current = getArray(); int len = current.length; if (snapshot != current) { // Optimize for lost race to another addXXX operation int common = Math.min(snapshot.length, len); for (int i = 0; i < common; i++) if (current[i] != snapshot[i] && eq(e, current[i])) return false; if (indexOf(e, current, common, len) >= 0) return false; } Object[] newElements = Arrays.copyOf(current, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } } //把空数组复制给对象 public void clear() { final ReentrantLock lock = this.lock; lock.lock(); try { setArray(new Object[0]); } finally { lock.unlock(); } } //对数组进行排序,先创建一个新的数组,对新数组排序后,新数组复制给对象 public void sort(Comparator<? super E> c) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); Object[] newElements = Arrays.copyOf(elements, elements.length); @SuppressWarnings("unchecked") E[] es = (E[])newElements; Arrays.sort(es, c); setArray(newElements); } finally { lock.unlock(); } } }
收藏文章数量从多到少与“把书读薄”是一个道理