java并发容器CopyOnWriteArrayList实现原理及源码分析

 更新时间:2017年05月22日 15:39:10   作者:dreamcatcher-cx  
这篇文章主要为大家详细介绍了java并发容器CopyOnWriteArrayList实现原理及源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器",Java并发包中类似的容器还有CopyOnWriteSet。本文会对CopyOnWriteArrayList的实现原理及源码进行分析。

实现原理

  我们都知道,集合框架中的ArrayList是非线程安全的,Vector虽是线程安全的,但由于简单粗暴的锁同步机制,性能较差。而CopyOnWriteArrayList则提供了另一种不同的并发处理策略(当然是针对特定的并发场景)。

  很多时候,我们的系统应对的都是读多写少的并发场景。CopyOnWriteArrayList容器允许并发读,读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。

  优缺点分析

  了解了CopyOnWriteArrayList的实现原理,分析它的优缺点及使用场景就很容易了。

  优点:

  读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景。Java的list在遍历时,若中途有别的线程对list容器进行修改,则会抛出ConcurrentModificationException异常。而CopyOnWriteArrayList由于其"读写分离"的思想,遍历和修改操作分别作用在不同的list容器,所以在使用迭代器进行遍历时候,也就不会抛出ConcurrentModificationException异常了

  缺点:

  缺点也很明显,一是内存占用问题,毕竟每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读和写的强一致性。而CopyOnWriteArrayList由于其实现策略的原因,写和读分别作用在新老不同容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据。

源码分析

  基本原理了解了,CopyOnWriteArrayList的代码实现看起来就很容易理解了。

public boolean add(E e) {
  //ReentrantLock加锁,保证线程安全
  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();
  }
 } 

  添加的逻辑很简单,先将原容器copy一份,然后在新副本上执行写操作,之后再切换引用。当然此过程是要加锁的。

  删除操作

public E remove(int index) {
  //加锁
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
   Object[] elements = getArray();
   int len = elements.length;
   E oldValue = get(elements, index);
   int numMoved = len - index - 1;
   if (numMoved == 0)
    //如果要删除的是列表末端数据,拷贝前len-1个数据到新副本上,再切换引用
    setArray(Arrays.copyOf(elements, len - 1));
   else {
    //否则,将除要删除元素之外的其他元素拷贝到新副本中,并切换引用
    Object[] newElements = new Object[len - 1];
    System.arraycopy(elements, 0, newElements, 0, index);
    System.arraycopy(elements, index + 1, newElements, index,
         numMoved);
    setArray(newElements);
   }
   return oldValue;
  } finally {
   //解锁
   lock.unlock();
  }
 }

  删除操作同理,将除要删除元素之外的其他元素拷贝到新副本中,然后切换引用,将原容器引用指向新副本。同属写操作,需要加锁。

  我们再来看看读操作,CopyOnWriteArrayList的读操作是不用加锁的,性能很高。

public E get(int index) {
  return get(getArray(), index);
 }
  直接读取即可,无需加锁

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

 总结

  本文对CopyOnWriteArrayList的实现原理和源码进行了分析,并对CopyOnWriteArrayList的优缺点也进行了分析(Java并发包中还提供了CopyOnWriteSet,原理类似)。其实所谓并发容器的优缺点,无非是取决于我们在面对特定并发场景时,是否能做出相对合理的选择和应用。也希望本文能帮助到有需要的童鞋,共勉。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • java微信公众号发送消息模板

    java微信公众号发送消息模板

    这篇文章主要为大家详细介绍了java微信公众号发送消息模板,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • Android、iOS和Java通用的AES128加密解密示例代码

    Android、iOS和Java通用的AES128加密解密示例代码

    现在很多App在与服务器接口的请求和响应过程中,为了安全都会涉及到加密和解密的问题,如果不加的话就会是明文的,即使加了GZIP也可以被直接解压成明文。如果同时有Android和IOS的App的话、必须要保证加密和解密的算法一致、不然后台没法处理,下面通过这篇文章学习下。
    2016-11-11
  • 浅谈SpringBoot项目打成war和jar的区别

    浅谈SpringBoot项目打成war和jar的区别

    这篇文章主要介绍了浅谈SpringBoot项目打成war和jar的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • java编程实现两个大数相加代码示例

    java编程实现两个大数相加代码示例

    这篇文章主要介绍了java编程实现两个大数相加代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-12-12
  • java网上图书商城(2)Category模块

    java网上图书商城(2)Category模块

    这篇文章主要介绍了java网上图书商城,Category模块,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • java screen的配置详解及注意事项

    java screen的配置详解及注意事项

    这篇文章主要介绍了java screen的配置详解及注意事项的相关资料,需要的朋友可以参考下
    2017-07-07
  • Intellij IDEA官方最完美编程字体Mono使用

    Intellij IDEA官方最完美编程字体Mono使用

    这篇文章主要介绍了Intellij IDEA官方最完美编程字体Mono使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Spring boot实现一个简单的ioc(1)

    Spring boot实现一个简单的ioc(1)

    这篇文章主要为大家详细介绍了Spring boot实现一个简单的ioc,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • 基于Spring AOP @AspectJ进阶说明

    基于Spring AOP @AspectJ进阶说明

    这篇文章主要介绍了基于Spring AOP @AspectJ进阶说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • SpringBoot 整合 Shiro 密码登录与邮件验证码登录功能(多 Realm 认证)

    SpringBoot 整合 Shiro 密码登录与邮件验证码登录功能(多 Realm

    这篇文章主要介绍了SpringBoot 整合 Shiro 密码登录与邮件验证码登录(多 Realm 认证),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02

最新评论