Collection集合04-CopyOnWriteArrayList
UML图
![](https://img2020.cnblogs.com/blog/1765333/202008/1765333-20200811215250101-564087995.png)
构造函数
-
默认是volatile修饰的Object数组;
-
默认是长度为0
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
private transient volatile Object[] array;
数据的存储和获取
1.add方法
-
扩容增加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);//复制扩容
newElements[len] = e;
setArray(newElements);//赋值成员变量
return true;
} finally {
lock.unlock();//关锁
}
}
final Object[] getArray() {
return array;
}
2.get方法
public E get(int index) {
return get(getArray(), index);
}
private E get(Object[] a, int index) {
return (E) a[index];
}
数据移除
-
移除index元素
-
将其他元素拷贝到新的数组,赋值成员变量
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)//如果长度只剩余1时
setArray(Arrays.copyOf(elements, len - 1)); //
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);//拷贝index前部分数据
System.arraycopy(elements, index + 1, newElements, index,numMoved);//拷贝index+1之后,
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
数据清空
- 赋值一个新的长度为0 的Object数组
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
setArray(new Object[0]);
} finally {
lock.unlock();
}
}
总结
看了几个常用的方法,进行总结:
-
初始化长度为0;
-
每新增一个元素就将生成一个长度+1的数组,将原数组赋值给新数组;
-
删除元素将删除的元素,之前的元素去键,和之后的元素区间进行拷贝。生成新的数组,将新数组进行赋值给类成员数组
优点:
-
线程安全,通过不公平锁进行线程加锁
-
有数组的所有优点,查找迅速。
缺点:
-
性能差
-
独占式锁操作比较耗时
-
频繁的对象创建,每增加一个元素或者删除一个元素都要新增一个对象数组
-