如果你想让ArrayList变得线程安全,你会怎么做?

目录

Collections.synchronizedList()

使用CopyOnWriteArrayList类

我们看更新操作的add源码

我们看读的操作get

它的优缺点

如何选择使用哪个


Collections.synchronizedList()

public static <T> List<T> synchronizedList(List<T> list) {
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list) :
                new SynchronizedList<>(list));
    }

然后再往下边点,你会发现,下边都是类似于这种

public int size() {
            synchronized (mutex) {return c.size();}
        }

全部使用synchronized锁

使用CopyOnWriteArrayList类

我们要了解什么是cow(CopyOnWrite)

写入时复制技术就是不同进程在访问同一资源的时候,只有更新操作,才会去复制一份新的数据并更新替换,否则都是访问同一个资源。

 了解了这一个简单的概念,那我们接着看源码就好理解了。

我们看更新操作的add源码

    public boolean add(E e) {
        //使用的是lock锁
        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;//index最后加上这个元素
            setArray(newElements); //新数组替换旧数组
            return true;
        } finally {
            lock.unlock(); //解锁
        }
    }

我们很清楚的看到,添加操作不仅加锁,而且多占用了一份内存(复制了旧数组)。其他更新操作思想和这个类似,就不再赘述。

我们看读的操作get

public E get(int index) {
        return get(getArray(), index);
    }

private E get(Object[] a, int index) {
        return (E) a[index];
    }

    //当前数组
    final Object[] getArray() {
        return array;
    }

这个操作就简单明了了,没有加锁,就是简单的拿数组中的元素。

它的优缺点

我们就很容易看到他的优缺点,它支持并发操作,读写分离,最终一致,但是消耗了更多的内存空间,如果数组过大,占中内存过多,或许还会报错。

如何选择使用哪个

其实从他们的特点我们就可以看出来,Collections.synchronizedList()无论什么情况都加锁,CopyOnWriteArrayList只在更新操作加锁,消耗更多内存。

如果我们是读多更新少的情况,就用CopyOnWriteArrayList。如果是读和更新差不多就用Collections.synchronizedList(),最后还是要根据实际业务来确认的,相信你看到这里心里也就有数了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值