CopyOnWriteArrayList源码分析
程序员文章站
2022-07-14 16:09:47
...
前两天刚分析完了ArrayList,趁热打铁,接着来看CopyOnWriteArrayList。
CopyOnWriteArrayList与ArrayList大部分的实现都是类似,只是在ArrayList的基础上加上了一个锁对象,对所有改变集合数据结构的操作加了同步代码块,现在的synchronized不再是之前那个稳定不变的mutex_lock重量级锁,而是借助mark_word等,在并发情况逐步升级锁,单线程情况就算加了synchronized关键字,性能就跟没写差不多。
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
final transient Object lock = new Object();
private transient volatile Object[] elements;
final Object[] getArray() {
return elements;
}
final void setArray(Object[] a) {
elements = a;
}
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
CopyOnWriteArrayList最大的特点就是"写时复制"。集合结构发生改变是先获取object 的锁,复制出一个新的数组,在新数组上进行操作,之后把新数组赋值给集合的数据字段,释放锁。 可以想到高并发的情况下,多个线程同时修改结构的操作是要竞争锁,但是同时的读取数据就没问题。实现的是读写分离,读在老数据上,写在新数据上,最后新数据数组覆盖老的。
读操作无须加锁,
// Positional Access Operations
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
static String outOfBounds(int index, int size) {
return "Index: " + index + ", Size: " + size;
}
public E get(int index) {
return get(getArray(), index);
}
写操作在新数组上操作,setArray 覆盖老数组。
public E set(int index, E element) {
synchronized (lock) {
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;
}
}
public boolean add(E e) {
synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
}
}
final void setArray(Object[] a) {
elements = a;
}
Arrays.copyOf 生成一个新的数组,并且复制原数据。
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}