CopyOnWriteArrayList和ArrayList源码区别分析

 public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }
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();
        }
    }

讨论两个问题
1、add如果不加锁,add 方法会产生的线程安全问题
答:其他线程会改变list的size,数组的容量,等等,会导致不管是if比较size也好,扩容也好,非原子操作,会导致每个步骤跟你期望的不一样,导致各种并发问题。

2、add方法直接操作原数组,会不会影响到get

也就是如下操作,能不能保证线程安全性。

public class TestList extends ArrayList {

    ReentrantLock lock = new ReentrantLock();

    @Override
    public boolean add(Object o) {
        lock.lock();
        boolean add = super.add(o);
        lock.unlock();
        return add;
    }
}

答:看ArrayList源代码,我个人感觉,可以保证,所以,为什么CopyOnWriteArrayList要重新复制一份数组出来,做这种低效能的事情,暂时存疑。
有一点,copyOnWriteArrayList的生成迭代器不会产生ConcurrentModifyException。

可以看到CopyOnWriteArrayList的缺点。
1、add是串行的,比较慢。也就是适合,写少读多的情况。
2、如果数组容量很大,每次add都要复制,会比较慢。

看ArrayList
可以看到,arraylist会进行扩容,每次扩容1.5倍。

 public boolean add(E e) {
        // 
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 扩容1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 扩容后还是小了,则直接为给定容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        // 如果容量达到了最大容量,则直接给最大容量
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

转载于:https://www.jianshu.com/p/d85000c98d71

猜你喜欢

转载自blog.csdn.net/weixin_34372728/article/details/91202642