- 依据jdk1.8源码分析
新建
- 创建一个零长度数组
private transient volatile Object[] array;//底层数据
添加数据
- 先上同步锁
- 对原始数组进行拷贝(浅拷贝),然后在拷贝后的数组上进行修改
- 将修改后的结果赋值给array
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();
}
}
获取数据
- 获取的时候没有加锁(由于array是volatile,所以会先从主内存更新数据,所以线程中的数据应该始终都是最新的)
删除数据
- 先上同步锁
- 对原始数据进行拷贝,在拷贝的时候不拷贝那个需要删除的数据
- 将修改后的结果赋值给array
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();
}
}
遍历数据
- 使用listIterator()获取迭代器
- listIterator()中将array赋给COWIterator(实现了ListIterator)。这里没有进行复制是因为如果数据有修改将生成一个新数组,而迭代中的数组将是一个过时的数组
- 可以调用hasNext() hasPrevious() next() previous()
- 注意:set() add() remove()都会直接抛出异常UnsupportedOperationException
总结
- 由于每次删除和增加元素都会拷贝一个新的数组出来,因此原本数组中的元素已经过时。所以即使这个时候另一个线程修改数据,也不会报错,只是数据不是最新的
- 增删改上锁、读不上锁
- 由于每一次修改都会有新的数组,array使用volatile修饰,所以在读的时候能确保使用的到的是最新的数组副本(多线程的情况下始终都是在主内存中读取)
参考jdk1.8源码
https://www.cnblogs.com/java-zhao/p/5121944.html