原理分析
继承类图
成员变量分析
只有两个属性
- 一个是ReentrantLock类型的变量
lock
- 另一个是一个Object类型的数组变量
array
主要方法分析
构造函数
setArray()
: 这个方法会被后面的构造方法调用,用来设置成员变量array的值
/**
* Sets the array.
*/
final void setArray(Object[] a) {
array = a;
}
CopyOnWriteArrayList()
:空参构造方法,可以初始化一个空数
/**
* Creates an empty list.
*/
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
CopyOnWriteArrayList(Collection<? extends E> c)
:传入一个集合类,可以把集合类转换成本类中的Object数组
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements;
//1. 判断传进来的集合是否为CopyOnWriteArrayList类型,如果是,直接赋值给elements
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
//2.1 先把传进来的集合类转换成数组
elements = c.toArray();
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elements.getClass() != Object[].class)
//2.2 把转换来的数组转换成Object类型的数组
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
setArray(elements);
}
CopyOnWriteArrayList(E[] toCopyIn)
:利用传入的数组来初始化array
public CopyOnWriteArrayList(E[] toCopyIn) {
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
增删方法
add方法
add(E e)
:传入一个元素,把这个元素放在数组的末尾
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//1. 加锁(非公平锁)
lock.lock();
try {
//2. 创建一个数组指针,指向当前list的数组对象
Object[] elements = getArray();
int len = elements.length;
//3. 创建一个新的数组对象,长度为当前数组长度+1,并且前面的length个元素都被copy到新数组中
Object[] newElements = Arrays.copyOf(elements, len + 1);
//4.让数组末尾的元素为新加入的元素
newElements[len] = e;
//5.设置新数组为array
setArray(newElements);
return true;
} finally {
//6. 解锁
lock.unlock();
}
}
add(int index, E element)
:在当前list的指定位置插入指定元素
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//1. 创建一个指向当前array的对象指针
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
//2. 定义新数组对象
Object[] newElements;
//3. 得到需要移动的元素数目
int numMoved = len - index;
//4. 如果要移动的元素是0的话直接当前数组长度加1就行
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
//5.如果要移动的元素非0的话要向右移动numMoved个元素
newElements = new Object[len + 1];
//5.1 先复制下标为 0-index 的元素在新数组中
System.arraycopy(elements, 0, newElements, 0, index);
//5.2 再复制下标为 index+1 - len的元素在新数组中
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}
get方法
public E get(int index) {
return get(getArray(), index);
}
remove方法
public E remove(int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//1. 创建一个指向当前array的对象指针
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
//2. 计算需要移动的元素数目
int numMoved = len - index - 1;
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
//复制elements从0开始,长度为index的元素
System.arraycopy(elements, 0, newElements, 0, index);
//复制elements从index+1开始,长度为numMoved的元素
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
扩展方法
java.lang.System#arraycopy:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
src:源数组;
srcPos:源数组要复制的起始位置;
dest:目的数组;
destPos:目的数组放置的起始位置;
length:复制的长度。
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
小结
- CopyOnWriteArrayList顾名思义,在写入操作时,copy源数组到新的数组中,而读取时,是从源数组去读的,因为写入操作是在另外一个数组中执行,因此在读取时,不用进行线程同步,但是要注意一点,copy数组的开销在数据量大的情况下,非常耗资源,因此,它的使用场景,适合于读取远大于写入操作的场景。当然,在写入时,是有锁的,JDK中的实现是采用重入显式锁进行锁定的。当写操作完成以后再将源数组的引用指向copy的数组,最后释放锁
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/202531.html