美文网首页
CopyOnWriteArrayList和ArrayList源码

CopyOnWriteArrayList和ArrayList源码

作者: 无聊之园 | 来源:发表于2019-05-31 10:35 被阅读0次
     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);
        }
    

    相关文章

      网友评论

          本文标题:CopyOnWriteArrayList和ArrayList源码

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