CopyOnWriteArrayList使用及实现原理

CopyOnWriteArrayList简介

CopyOnWriteArrayList是线程安全List,具有常见集合的API,当在读多写少时并且服务器内存够用的情况下非常便于使用。

CopyOnWriteArrayList使用及其场景

在这里插入图片描述由于CopyOnWriteArrayList实现了List接口所以,CopyOnWriteArrayList也有常见操作集合的方法如add(),remove()。
在我做的一个项目中, 需要存放学生考试信息。刚开始没有考虑多线程的影响。就采用了如下方式:

  //用于存放考试学生信息ArrayList
    public  static  List<Map<String,Object>> sessionList = new ArrayList<>();

但每次重启服务时,都会报一个错误:ConcurrentModificationExceptionError解决办法请移步
这是由于每次项目重启,定时器就会有多个任务会执行,这时不仅有读的线程去操作学生信息ArrayList,而且还会有写的线程去操作学生信息ArrayList。

  //用于存放考试学生信息CopyOnWriteArrayList
    public  static  List<Map<String,Object>> sessionList = new CopyOnWriteArrayList<>();

所以我将ArrayList换为CopyOnWriteArrayList。之后这个问题就解决了。

CopyOnWriteArrayList实现原理

那么为什么使用CopyOnWriteArrayList就没有问题呢?那我们现在看看CopyOnWriteArrayList的源码。

public boolean add(E e) {
		//获取可重入锁
        final ReentrantLock lock = this.lock;
        //加锁
        lock.lock();
        try {
        	//获取原有数组
            Object[] elements = getArray();
            int len = elements.length;
            //将原有数组复制一份,并将长度加1
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            //添加元素
            newElements[len] = e;
            //将原来数组对象的引用指向新的数组
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
/**
 * Sets the array.
 */
final void setArray(Object[] a) {
	//将数组引用指向新的数组
    array = a;
}
public E get(int index) {
    return get(getArray(), index);
}

private E get(Object[] a, int index) {
	//直接获取元素
    return (E) a[index];
}

看源码我们得知:每次添加元素就会复制一份数组副本在内存空间,当添加操作完成,再将数组的引用指向新的数组,这样就不存在又在读又在写的情况。(读的线程操作原始数组,写的线程操作复制的副本数组)
在这里插入图片描述
但这里会存在数据一致性问题:只能保证数据最终一致性问题,不能保证数据实时一致性问题。
由于读时一直在进行V1,而写随时可能进行v2,我们只会在写完后才回去改变引用指向新的对象v2。这个过程中读就是一直读的上个一个版本v1。如果实际场景不符则需要采用其他线程安全集合。

CopyOnWriteArrayList总结

CopyOnwrite适用于读极多(读的并发量很多),写极少(写的性能很低)。由于每次都是将数组重新复制一份,当一个数组里面数据量很大时,这时在复制一个副本就容易造成GC;会存在数据一致性问题:只能保证数据最终一致性问题,不能保证数据实时一致性问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值