CopyOnWriteArrayList

常用方法分析

add 添加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public boolean add(E e) {
// 获取独占锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 获取原来的数组
Object[] elements = getArray();
int len = elements.length;
// 复制元素到新数组,新数组长度是原来数组长度的+1
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}

获取指定位置的元素

1
2
3
public E get(int index) {
return get(getArray(), index);
}
1
2
3
final Object[] getArray() {
return array;
}
1
2
3
private E get(Object[] a, int index) {
return (E) a[index];
}

get方法没有加锁,如果一个线程在获取元素的同时有一个线程删除了某些元素,那么会产生弱一致性问题,弱一致性是指返回迭代器后,其他线程对list的增删改查是不可见的

指定位置修改值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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();
}
}

删除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
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 oldValue;
} finally {
lock.unlock();
}
}

总结

CopyOnWriteArrayList的增删改的操作都加入锁,且进行了复制数组的操作。