public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// ReentrantLock 可重入锁 ,保证线程安全
//transient让定义的变量不被序列化
final transient ReentrantLock lock = new ReentrantLock();
private transient volatile Object[] array;
//获取数组
final Object[] getArray() {
return array;
}
final void setArray(Object[] a) {
array = a;
}
一、无参构造
作用: 创建一个空数组
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
二、获取元素get()
获取元素[读取元素]过程中不加锁,允许多个线程获取
如果获取过程中 ,其他线程向集合中添加新元素,此时读取到的是旧数据
因为添加操作没有对原数组加锁
2.1、根据下标获取元素
public E get(int index) {
return get(getArray(), index);
}
2.2、根据传入的数组和指定下标,返回该数组中指定下标的元素
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
三、set(index,element)
1.获取锁 【在同一时间只允许一个线程访问】
2.使用elements数组 来存储 原数组
3.调用get(element,index)得到指定下标的原来元素值 :oldValue;
4.判断传入的值与old Value是否一致
若不一致:进入if 语句块中 :
先获取原数组长度创建新数组newElements, 再将原数组内容赋值到 新的数组中
再将传入的新值替换到新数组中指定下标的元素中
最后将原数组的引用指向新的数组
若一致:执行else块:
将原数组的引用指向elements数组
5.将指定下标位置的旧值返回
6.释放锁
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();
}
}
四、新元素添加
整体逻辑:
将原来的数组复制Copy 到新数组中 ,将新元素追加至末尾位置,最后替换原数组
会加锁,来保证线程安全
add(E e)
1.获取原数组并得到其长度
2.将原数组复制到欣数组中
3.将传入的新元素追加到最后
4.原数组引用新数组
5.如果添加成功 返回TRUE;
6.最后释放锁
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();
}
}
add(index ,e) 方法重载
1.加锁 获取原数组【以及长度】
2.判断传入的index【位置】是否合法,如果非法【大于长度或或者小于0】,则抛出异常
3.计算需要移动的元素个数numMoved 【len - index】
若 = 0 ,表示新元素的下标 在数组的最后位置,
此时:使用Arrays类复制原数组至新数组,长度加1
否则 :
创建新数组,其长度比原数组多1
将0到index位置的元素复制到新数组的指定位置
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];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}
remove(index)
功能:删除指定下标元素
整体逻辑:根据指定下标,从原数组中,Copy复制其它元素至新数组中,最后替换原数组
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();
}
}
removeRange(fromIndex,toIndex)
功能:按照指定范围删除元素
1.加锁 获取原数组【以及长度】
2.判断传入删除位置【index】是否合法,如果非法【大于长度或或者小于0】,则抛出异常
3. 不满足则抛出异常
4.计算新数组的长度 = len -(toIndex-fromIndex)
5. 计算需要移动的元素个数numMoved 【len -toindex】
5.1、若 numMoved= 0 ,表示需要移动的元素个数为0【删除范围在元素组最后】
使用Arrays类复制原数组至新数组,长度加1
5.2、 否则 :【元素组分为两部分--->将这两部分的元素复制至新数组中】
创建新数组,其长度为newlen,
前段: 将原数组从0位置开始后fromIndex个元素复制至新数组【从0开始】
后端: 将原数组从toIndex位置开始后numMoved个元素复制至新数组【从 fromIndex开始】
6.改变原数组引用【将指向新数组】
7.最后 关闭锁
void removeRange(int fromIndex, int toIndex) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
throw new IndexOutOfBoundsException();
int newlen = len - (toIndex - fromIndex);
int numMoved = len - toIndex;
if (numMoved == 0)
setArray(Arrays.copyOf(elements, newlen));
else {
Object[] newElements = new Object[newlen];
System.arraycopy(elements, 0, newElements, 0, fromIndex);
System.arraycopy(elements, toIndex, newElements,
fromIndex, numMoved);
setArray(newElements);
}
} finally {
lock.unlock();
}
}
removeAll(Collection<?> c)
功能:传入一个集合,删除元素组中该集合中的所有元素【去交集】
1.判断传入集合c是否为空指针,满足抛出异常
若传入集合c为空,则返回false ,
2.定义并加锁
3.获取元素组及长度
4.判断长度是否为0
若不为0,定义临时数组temp,长度为数组长度
开始遍历数组,获取每一个元素
判断集合中是否包含该元素 :若不包含,判断下一个,并将该元素以此存入temp临时数组中
5.如果临时数组的长度newlen不等于原数组长度len
将temp数组中的newlen个元素复制到新数组中,再将引用传给原数组
6.返回
public boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (len != 0) {
// temp array holds those elements we know we want to keep
int newlen = 0;
Object[] temp = new Object[len];
for (int i = 0; i < len; ++i) {
Object element = elements[i];
if (!c.contains(element))
temp[newlen++] = element;
}
if (newlen != len) {
setArray(Arrays.copyOf(temp, newlen));
return true;
}
}
return false;
} finally {
lock.unlock();
}
}
clear()
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
setArray(new Object[0]);
} finally {
lock.unlock();
}
}