copyOnWriteArrayList Vector 源码分析

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的安全性和效率都会高一点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CopyOnWriteArrayListVector都是线程安全的List实现,但它们之间有一些区别: 1. 内部实现机制: - CopyOnWriteArrayList使用了"写时复制"(Copy-On-Write)的机制。即当进行写操作时,会创建一个新的副本数组,并在副本上进行修改,而原数组保持不变。这样可以保证读操作的线程安全性,但写操作会导致创建新的副本数组,因此内存消耗较大。 - Vector使用synchronized关键字对所有方法进行同步,保证了线程安全性。但是这也导致了在并发情况下的性能相对较低。 2. 性能: - CopyOnWriteArrayList在读操作方面性能较好,因为读操作不需要加锁,并且多个线程可以同时读取。 - Vector在读操作方面性能较差,因为所有方法都使用了同步锁,需要等待其他线程释放锁才能继续执行。 3. 扩容机制: - CopyOnWriteArrayList在进行写操作时,会创建一个新的副本数组,并在新数组上进行修改,不需要像ArrayList那样进行扩容操作。 - Vector在进行扩容时,会创建一个新的数组,并将原有元素复制到新数组中。 4. 迭代器支持: - CopyOnWriteArrayList的迭代器是弱一致性的,即在迭代过程中可以看到修改操作之前的数据,但不能保证迭代期间的数据一致性。 - Vector的迭代器是快速失败的,即在迭代过程中如果有其他线程对Vector进行修改,会抛出ConcurrentModificationException异常。 综上所述,CopyOnWriteArrayList适用于读多写少的场景,并且对于迭代器的一致性要求相对较低;而Vector适用于需要严格的线程安全性和快速失败迭代的场景,但性能相对较低。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值