java.util.concurrent包中定义常见集合类对应的并发集合类,用于高效处理并发场景,其中CopyOnWriteArrayList对应就是ArrayList。顾名思义CopyOnWrite,写时拷贝,这里写包括对集合类的修改操作,都会创建一个副本。
CopyOnWriteArrayList的实现
类的定义
public class CopyOnWriteArrayList可以看到没有继承任何子类,实现接口和ArrayList类似。implements List , RandomAccess, Cloneable, java.io.Serializable
关键属性
/** The lock protecting all mutators */ transient final ReentrantLock lock = new ReentrantLock(); /** The array, accessed only via getArray/setArray. */ private volatile transient Object[] array;同样是采用数组方式实现,多了一个volatile声明,用于保证线程可见性。没有size声明表示实际包含元素的大小,多了一个ReentrantLock对象声明。
常见方法
构造方法
public CopyOnWriteArrayList() {
setArray(new Object[0]); //默认创建一个空数组
}
public CopyOnWriteArrayList(Collection
c) {
Object[] 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);
}size方法,直接返回数组大小,说明array数组只包含实际大小的空间
public int size() {
return getArray().length;
}get方法,和ArrayList中类似,不过没有index的范围判断
public E get(int index) {
return (E)(getArray()[index]);
}add方法,可以看到无论是在尾部还是指定位置添加,都有锁定和解锁操作,在设置值之前都先将原先数组拷贝一份并扩容至size+1大小。
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);//拷贝array属性,并扩展为length+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;
if (numMoved == 0) //尾部添加
newElements = Arrays.copyOf(elements, len + 1);
else {
newElements = new Object[len + 1];
//elements[0,index) ---> newElements[0,index)
System.arraycopy(elements, 0, newElements, 0, index);
//elements[index,len) --> newElements[index+1,len+1)
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}set方法,ArrayList中set方法直接改变数组中对应的引用,这里需要拷贝数组然后再设置。(else那个分支没看懂,为什么值没有改变还需要设置来保证volatile写语义)
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
setArray(elements);
}
return (E)oldValue;
} finally {
lock.unlock();
}
}remove(int)方法,和指定位置添加类似,需要拷贝[0,index)和[index+1,len)之间的元素
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;nt
if (numMoved == 0) //删除最后一个元素
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
//elements[0,index) --> newElements[0,index)
System.arraycopy(elements, 0, newElements, 0, index);
//elements[index+1,len) --> newElements[index,len-1)
System.arraycopy(elements, index + 1, newE