美文网首页
大话CopyOnWriteArrayList

大话CopyOnWriteArrayList

作者: kele2018 | 来源:发表于2024-07-01 14:25 被阅读0次

CopyOnWriteArrayList是JUC中比较简单的一个类,可以理解为线程安全的ArrayList,所以假如理解了ArrayList的不安全性,也就理解了CopyOnWriteArrayList。
为什么说ArrayList是线程不安全的?
ArrayList底层使用的数据结构是数组,数组有容量和下标;比如说现在数组的容量是10,里面已经添加了9个元素;此时A和B两个线程同时向数组中添加元素,A线程判断数组中还有几个元素,发现还有一个位置,于是准备添加元素,而B线程也发现还有一个位置,也准备添加元素,那么最后的结果要么是数组越界,要么AB两个线程元素互相覆盖。

参考代码
public boolean add(E e) {
     ensureCapacityInternal(size + 1);  // 确认是否有位置
     elementData[size++] = e; // 添加元素
     return true;
 }

CopyOnWriteArrayList:增

// 假如没有指定下标 则添加到数组最后一个位置
public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock(); // 由于加锁过程中有可能出错,所以一定要放到try外
    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();
    }
}

 // 在确定索引添加元素  
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();
    }
}
// 在末尾添加一批元素
public boolean addAll(Collection<? extends E> c) {}
// 从指定位置开始添加一批元素
public boolean addAll(int index, Collection<? extends E> c) {}
// 如果不存在就添加
public boolean addIfAbsent(E e) {}

CopyOnWriteArrayList:删

// 删除指定位置
public E remove(int index) {}
// 删除指定元素
public boolean remove(Object o) {}
// 删除一批元素
public boolean removeAll(Collection<?> c) {}

CopyOnWriteArrayList:改

/**
1、同一时间只能有一个线程执行修改操作;
2、为了不影响查,把原来的数组复制一份出来,在新的数组上修改;
**/
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 {
            setArray(elements);   //  根据happens-before原则,这里应该volatile写一下   
        }
        return oldValue;  // 一旦修改成功旧值就找不到了,所以这里返回旧值,以防后面还需要使用旧值----好想法,具有借鉴意义
    } finally {
        lock.unlock();
    }
}

CopyOnWriteArrayList:查

优点:
1、读不加锁,比Vector,SynchronizedList性能高;
2、以空间换时间,提升性能;

缺点:
1、写操作多,会消耗很多内存;
2、读延迟;

适用场景:读多写少

相关文章

网友评论

      本文标题:大话CopyOnWriteArrayList

      本文链接:https://www.haomeiwen.com/subject/rxrmcjtx.html