private volatile transient Object[] array; final Object[] getArray() { return array; } final void setArray(Object[] a) { array = a; }
- CopyOnWriteArrayList():构造一个内容为空的对象
- CopyOnWriteArrayList(Collection<? extends E> c):根据传入参数中的内容,构造一个新的对象
- CopyOnWriteArrayList(E[] toCopyIn):根据传入数组中的内容,构造一个新的对象
public CopyOnWriteArrayList() { setArray(new Object[0]); } /** * 根据传入参数c的长度,构造一个同样长度的Object[]对象,并且将c的内容,依次填入此Object[]对象中
* 注意:
* 1. 这里对于c中内容的复制,是浅拷贝而非深拷贝
* 2. 这里的构造函数,未显式判断c是否为null,实际上如果c为null,会抛出空指针异常 */ public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements = c.toArray(); if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); setArray(elements); } /** * 根据传入参数的长度,构造出一个同样长度,内容一致的数组对象,封装在CopyOnWriteArrayList中
* 注意:
* 1. 这里对于数组内容的复制,是浅拷贝而非深拷贝
* 2. 这里的构造函数,未显式判断传入参数是否为null,实际上如果传入参数为null,会抛出空指针异常 */ public CopyOnWriteArrayList(E[] toCopyIn) { setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); }
public E get(int index) { return (E)(getArray()[index]); }
public int indexOf(Object o) { /*
* 在取数组元素前,获取当前时刻array对象的引用至关重要
* 在后续文章描述中可以知道,CopyOnArrayList在set操作时,会更新array对象的引用
* 这里如果不事先获得引用,那么后面实际的indexOf操作,会因为并发问题,得到意想不到的结果,还可能出现数组越界异常
*/ Object[] elements = getArray(); return indexOf(o, elements, 0, elements.length); }
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; }
public Object[] toArray() { Object[] elements = getArray(); return Arrays.copyOf(elements, elements.length); }
public <T> T[] toArray(T a[]) { Object[] elements = getArray(); int len = elements.length; if (a.length < len) return (T[]) Arrays.copyOf(elements, len, a.getClass()); else { System.arraycopy(elements, 0, a, 0, len); if (a.length > len) a[len] = null; return a; } }
public Object clone() { try { CopyOnWriteArrayList c = (CopyOnWriteArrayList)(super.clone()); c.resetLock(); return c; } catch (CloneNotSupportedException e) {
/* 实际不会发生,但因为clone()接口声明返回此异常,所以这里会这样写 */ throw new InternalError(); } }
写操作的并发安全性
public E set(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); /* 锁定整个数组,不允许其他写操作同时进行,否则会出现丢失更新的问题 */ try { Object[] elements = getArray(); Object oldValue = 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
* 个人理解,这个地方没什么作用,只是为了部全set的语义
*/ setArray(elements); } return (E)oldValue; } finally { lock.unlock(); } }
同时,也可以将某个元素加入到某个特定的位置,如下所示: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(); } }
public void add(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length;
/* 这个判断必须放到lock内,否则在多线程并发访问条件下,可能会出现错误,
* 例如,一个线程判断其不会抛出异常,另一个线程立即修改了数组长度,导致后续操作均会失败
*/ if (index > len || index < 0) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+len); Object[] newElements; int numMoved = len - index; if (numMoved == 0) { /* 插入元素的位置,在数组末尾 */ newElements = Arrays.copyOf(elements, len + 1);
} else {
/* 插入元素的位置,在数组中间 */ 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(); } }
也可以直接移除list中的某个对象,源码如下:public E remove(int index) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object oldValue = elements[index]; int numMoved = len - index - 1; 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 (E)oldValue; } finally { lock.unlock(); } }
其他修改的方法,原理上都是类似的,这里不再赘述。sspublic 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])) { /* 如果需要移除的元素在数组中间,那么直接将后面的所有元素向前移动 */ for (int k = i + 1; k < len; ++k) { newElements[k-1] = elements[k];
} setArray(newElements); return true; /* 找到了需要删除的元素,并正常删除,返回true */ } else { newElements[i] = elements[i];
} } /* 当需要移除的元素,在数组最后,直接将新的数组赋值过去 */ if (eq(o, elements[newlen])) { setArray(newElements); return true; } }
/* 未找到需要删除的元素,返回false */ return false; } finally { lock.unlock(); } }