copyOnWriteArrayList Vector 源码分析

    技术2022-07-15  78

    copyOnWriteArrayList与Vector都是用来替换多线程下List的使用的 这里通过源码分析一下他们的实现

    Vector 底层为数组实现 初始容量为10

    //第一个参数为数组初始大小,第二个参数为扩容时需要增加的大小 public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }

    而它对于增加和删除元素,是通过加锁来保证多线程下的安全性的,如超过默认大小 则进行扩容

    public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }

    扩容时 如果构造时未指定每次扩容的大小,则扩为原来二倍

    private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }

    由于加锁的缘故,大多情况下时能保证线程安全的,但是,在这种情况下不行,如下:

    // 之所以不行的原因是当某个线程获取到这个锁, //判断完之后释放了,但是到执行add还是有间隔, //所以有可能会被另一个线程获取,然后时间片段结束后释放 if(Vector.contains(1)){ Vector.add(2) }

    所以,对于Vector的线程安全性,还需要自己代码加锁来保证,这样的话,首先是加锁会大大降低效率,其次也并没有完全保证线程安全,所以推荐使用下面的copyOnWriteArrayList

    CopyOnWriteArrayList

    它底层也是用数组实现,但是它和Vector最大的不同以及优于它的一点就在于它对于add/remove元素,并不在方法上面加锁,它采用的是方法内用重入锁,创建新数组并将原数组复制到新数组,将元素添加到新数组,将引用指向新数组,解锁。具体源码如下:

    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(); } }

    它比Vector的安全性和效率都会高一点

    Processed: 0.013, SQL: 9