JDK源码解析之ArrayList与Vector与CopyOnWriteArrayList

1.  ArrayList的线程安全问题:

    public static void main(String[] args) {
        final List<Integer> list = new ArrayList<Integer>();
        for (int i=0;i<5000;i++) {
            list.add(i);
        }
        //开始5个线程,每个线程添加1000个数据
        for(int i=0;i<5;i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int j=0;j<1000;j++){
                        list.add(j);
                    }
                }
            }).start();
        }

        //开启5个线程,每个线程删除1000个数据
        for (int i=0;i<5;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int j=0;j<1000;j++){
                        list.remove(0);
                    }
                }
            }).start();
        }
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {}
        System.out.printf("list size="+list.size());
    }

运行发现结果不是5000,每次运行的结果可能都不一样,如果换成vector呢结果就会得到想要的5000,换成CopyOnWriteArrayList也可以得到想要结果,既然Vector和CopyOnWriteArrayList都是线程安全的,那他两有什么不同呢

 

2.  Vector的实现:

a. vector的方法是synchronized的,也就是线程安全的,这也会导致其性能比ArrayList低

b. Vector扩容比ArrayList大,每次扩容为1倍而ArrayList为0.5倍,这就说明当初始化容量不足时,ArrayList更节省空间,源码如下:

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}
private void ensureCapacityHelper(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object[] oldData = elementData;
        int newCapacity = (capacityIncrement > 0) ?
                (oldCapacity + capacityIncrement) : (oldCapacity * 2);
        if (newCapacity < minCapacity) {
            newCapacity = minCapacity;
        }
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

c. Vector和ArrayList一样不支持读写并发操作,否则会抛出并发异常ConcurrentModificationException,这个需要注意的

3.  CopyOnWriteArrayList的实现:

a.  使用ReentrantLock锁保证线程安全,CopyOnWriteArrayList新增时会新建一个数组添加,添加完成后再将原数组指向新的数组,这就导致内存占用问题,如果对象比较大可能会导致频繁发生Yong GC和Full GC,使用时需要注意内存问题

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();
    }
}
final void setArray(Object[] a) {
    array = a;
}

b. CopyOnWriteArrayList的这种读写分离机制没有锁定原数组,也就是可以同时读取原数组数据,不过读取的是修改前的旧数据,达到了读写并发要求

public E get(int index) {
    return (E)(getArray()[index]);
}
final Object[] getArray() {
    return array;
}

c . CopyOnWriteArrayList能保证数据的最终一致性,但不能保证数据的实时一致性,这个需注意

4. 总结

a.  ArrayList是线程不安全的

b.  Vector线程安全,但性能低

c.  CopyOnWriteArrayList线程安全,性能高同时支持并发操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值