Collections.synchronizedList 、CopyOnWriteArrayList、Vector介绍、源码浅析与性能对比【文末福利】

本文分析了ArrayList的线程安全问题,介绍了Vector、Collections.synchronizedList和CopyOnWriteArrayList的线程安全实现机制。Vector通过在方法上加关键字实现,效率较低;Collections.synchronizedList提供了线程安全的List包装,但迭代需手动加锁;CopyOnWriteArrayList适合读多写少的场景,写操作会复制数组,性能较低。性能测试显示,CopyOnWriteArrayList的遍历和写操作性能消耗大,而读写性能与synchronizedList相近。
摘要由CSDN通过智能技术生成

ArrayList线程安全问题

众所周知,ArrayList不是线程安全的,在并发场景使用ArrayList可能会导致add内容为null,迭代时并发修改list内容抛ConcurrentModificationException异常等问题。java类库里面提供了以下三个轮子可以实现线程安全的List,它们是

  • Vector
  • Collections.synchronizedList
  • CopyOnWriteArrayList

本文简要的分析了下它们线程安全的实现机制并对它们的读,写,迭代性能进行了对比。

Vector

从JDK1.0开始,Vector便存在JDK中,Vector是一个线程安全的列表,底层采用数组实现。其线程安全的实现方式非常粗暴:Vector大部分方法和ArrayList都是相同的,只是加上了synchronized关键字,这种方式严重影响效率,因此,不再推荐使用Vector了。JAVA官方文档中这样描述:

If a thread-safe implementation is not needed, it is recommended to use ArrayList in place of Vector.

如果不需要线程安全性,推荐使用ArrayList替代Vector

关键源码如下:

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

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

public synchronized Iterator<E> iterator() {
   
    return new Itr();
}    

可以看到Vector通过在方法级别上加入了synchronized关键字实现线程安全性。

Collections.synchronizedList

因为ArrayList不是线程安全的,JDK提供了一个Collections.synchronizedList静态方法将一个非线程安全的List(并不仅限ArrayList)包装为线程安全的List。使用方式如下:

List list = Collections.synchronizedList(new ArrayList());

根据文档,转换包装后的list可以实现add,remove,get等操作的线程安全性,但是对于迭代操作,Collections.synchronizedList并没有提供相关机制,所以迭代时需要对包装后的list(敲黑板,必须对包装后的list进行加锁,锁其他的不行)进行手动加锁,使用方式如下:

List list = Collections.synchronizedList(new ArrayList());
//必须对list进行加锁
synchronized (list) {
   
  Iterator i = list.iterator();
  while (i.hasNext())
      foo(i.next());
}

这个地方要注意两个地方:

  1. 迭代操作必须加锁,可以使用synchronized关键字修饰;
  2. synchronized持有的监视器对象必须是synchronized (list),即包装后的list,使用其他对象如synchronized (new Object())会使add,remove等方法与迭代方法使用的锁不一致,无法实现完全的线程安全性。

通过源码可知Collections.synchronizedList生成了特定同步的SynchronizedCollection,生成的集合每个同步操作都是持有mutex这个锁,所以再进行操作时就是线程安全的集合了。关键地方已经加了注释:

public static <T> List<T> synchronizedList(List<T> list) {
   
    return (list instanceof RandomAccess ?
            //ArrayList使用了SynchronizedRandomAccessList类
            
  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值