在上篇文章中我们已经介绍了其他的一些list集合,如ArrayList、linkedlist等。不清楚的可以看下上篇文章www.jianshu.com/p/6227ab5b3… 但是向ArrayList这些会出现线程不安全的问题,我们该怎样解决呢?接下来就是要介绍我们线程安全的list集合synchronizedList和CopyOnWriteArrayList。

一、synchronizedList

synchronizedList的使用方式:

public void test(){ArrayList<String> list = new ArrayList<>();List<String> sycList = Collections.synchronizedList(list);sycList.add("a");sycList.remove("a");}
复制代码

从上面的使用方式中我们可以看出,synchronizedList是将List集合作为参数来创建的synchronizedList集合。

synchronizedList为什么是线程安全的呢? 我们先来看一下他的源码:

        @Overridepublic int size() {synchronized(mutex) {return backingList.size();}}@Overridepublic boolean isEmpty() {synchronized(mutex) {return backingList.isEmpty();}}@Overridepublic Object[] toArray() {synchronized(mutex)  {return backingList.toArray();}}@Overridepublic boolean add(T e) {synchronized(mutex) {return backingList.add(e);}}@Overridepublic boolean remove(Object o) {synchronized(mutex) {return backingList.remove(o);}}
复制代码

我们大概贴了一些常用方法的源码,从上面的源码中我们可以看出,其实synchronizedList线程安全的原因是因为它几乎在每个方法中都使用了synchronized同步锁。

synchronizedList遍历为什么还需要加锁?

synchronizedList官方文档中给出的使用方式是以下方式:

List list = Collections.synchronizedList(new ArrayList());...synchronized (list) {Iterator i = list.iterator(); // Must be in synchronized blockwhile (i.hasNext())foo(i.next());}
复制代码

在以上源码中我们可以看出,官方文档是建议我们在遍历的时候加锁处理的。但是既然内部方法以及加了锁,为什么在遍历的时候还需要加锁呢?我们来看一下它的遍历方法:

        @Overridepublic Iterator<T> iterator() {return backingList.iterator();}
复制代码

从以上源码可以看出,虽然内部方法中大部分都已经加了锁,但是iterator方法却没有加锁处理。那么如果我们在遍历的时候不加锁会导致什么问题呢? 试想我们在遍历的时候,不加锁的情况下,如果此时有其他线程对此集合进行add或者remove操作,那么这个时候就会导致数据丢失或者是脏数据的问题,所以如果我们对数据的要求较高,想要避免这方面问题的话,在遍历的时候也需要加锁进行处理。 但是既然是使用synchronized加锁进行处理的,那肯定避免不了一些锁开销。有没有效率更好的方式呢?那就是我们另一个主要的并发集合CopyOnWriteArrayList。

二、CopyOnWriteArrayList

CopyOnWriteArrayList是在执行修改操作时,copy一份新的数组进行相关的操作,在执行完修改操作后将原来集合指向新的集合来完成修改操作。具体源码如下:

    /** The array, accessed only via getArray/setArray. */  private volatile transient Object[] array;//保证了线程的可见性  public void add(int index, E element) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;if (index > len || index < 0)throw new IndexOutOfBoundsException("Index: "+index+", Size: "+len);Object[] newElements;int numMoved = len - index;if (numMoved == 0)newElements = Arrays.copyOf(elements, len + 1);  //copy一份比当前数组长度+1的array数组else {newElements = new Object[len + 1];         //将add的参数赋值System.arraycopy(elements, 0, newElements, 0, index);System.arraycopy(elements, index, newElements, index + 1,numMoved);}newElements[index] = element;setArray(newElements);           //将原数组指向新的数组} finally {lock.unlock();}}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)setArray(Arrays.copyOf(elements, len - 1));    //copy一份比当前数组长度-1的array数组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();}}/*** 将原数组指向新的数组*/final void setArray(Object[] a) {array = a;}复制代码

从以上源码我们可以看出,它在执行add方法和remove方法的时候,分别创建了一个当前数组长度+1和-1的数组,将数据copy到新数组中,然后执行修改操作。修改完之后调用setArray方法来指向新的数组。在整个过程中是使用ReentrantLock可重入锁来保证不会有多个线程同时copy一个新的数组,从而造成的混乱。并且使用volatile修饰数组来保证修改后的可见性。读写操作互不影响,所以在整个过程中整个效率是非常高的。

总结

synchronizedList适合对数据要求较高的情况,但是因为读写全都加锁,所有效率较低。 CopyOnWriteArrayList效率较高,适合读多写少的场景,因为在读的时候读的是旧集合,所以它的实时性不高。

转载于:https://juejin.im/post/5d40105ae51d4561c273a649

线程安全的list之synchronizedList和CopyOnWriteArrayList相关推荐

  1. 如何线程安全地遍历List:Vector、CopyOnWriteArrayList

    原文链接:http://blog.csdn.net/xiao__gui/article/details/51050793 遍历List的多种方式 在讲如何线程安全地遍历List之前,先看看通常我们遍历 ...

  2. java 多线程遍历list_如何线程安全地遍历List:Vector、CopyOnWriteArrayList

    遍历List的多种方式 在讲如何线程安全地遍历List之前,先看看通常我们遍历一个List会采用哪些方式. 方式一: for(int i = 0; i < list.size(); i++) { ...

  3. 如何把class里的vector结构体memcpy出来_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector...

    以下环境是 JDK 1.8 ArrayList 的初始容量 面试官:你看过 ArrayList 的源码? Python 小星:看过 面试官:那你说下ArrayList 的初始容量是多少? Python ...

  4. arraylist 后往前遍历_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector

    以下环境是 JDK 1.8 ArrayList 的初始容量 面试官:你看过 ArrayList 的源码? Python 小星:看过 面试官:那你说下ArrayList 的初始容量是多少? Python ...

  5. JDK1.8源码分析:线程安全的CopyOnWriteArrayList与CopyOnWriteArraySet

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:服务端开发 blog.csdn.net/u01001 ...

  6. 全网最细 | 21张图带你领略集合的线程不安全

    来源 | 悟空聊架构(ID:PassJava666) 本篇主要内容如下: 本篇主要内容 本篇所有示例代码已更新到 我的Github 本篇文章已收纳到我的Java在线文档 集合,准备团战 一.线程不安全 ...

  7. 超详细 | 21张图带你领略集合的线程不安全

    来源 | 悟空聊架构 本篇主要内容如下: 本篇主要内容 本篇所有示例代码已更新到 我的Github 本篇文章已收纳到我的Java在线文档 线程不安全之ArrayList 集合框架有Map和Collec ...

  8. 「源码分析」CopyOnWriteArrayList 中的隐藏知识,你Get了吗?

    前言 本觉 CopyOnWriteArrayList 过于简单,寻思看名字就能知道内部的实现逻辑,所以没有写这篇文章的想法,最近又仔细看了下 CopyOnWriteArrayList 的源码实现,大体 ...

  9. Java面试之ArrayList为什么线程不安全?

    Collection线程不安全的举例 前言 1.当我们执行下面语句的时候,底层进行了什么操作 new ArrayList<Integer>(); 底层创建了一个空的数组,伴随着初始值为10 ...

  10. 集合的get方法中参数从多少开始_源码分析CopyOnWriteArrayList 中的隐藏知识,你Get了吗?...

    欢迎点击 "未读代码" ,关注公众号,文章每周更新 杭州-阿里园区墙 前言 本觉 CopyOnWriteArrayList 过于简单,寻思看名字就能知道内部的实现逻辑,所以没有写这 ...

最新文章

  1. 【译】TCP Implementation in Linux
  2. boost::mp11::mp_rotate_right相关用法的测试程序
  3. 品牌管理-统一异常处理
  4. 软件设计师-不确定有限自动机到确定有限自动机转换的例子
  5. 【Koa】Error: Cannot find module ‘koa-router‘
  6. 【转】HEIF图片存储格式探秘
  7. 平安普惠系统上线申请表模板
  8. 信息安全方面优秀论文
  9. 腾讯公布员工数据:超 30 岁员工占近六成
  10. 漫画:什么是ConcurrentHashMap?
  11. android 最新 九宫格,Android开发中怎么显示一个九宫格图片
  12. Windows计算机操作系统基础知识点总结
  13. 关于数据库中FK的简单理解以及应用
  14. 士兵队列训练问题 (队列 c++)
  15. 剖析Vue实现双向数据绑定原理
  16. 东南大学计算机科学与技术夏令营,2019东南大学网络空间安全学院夏令营招生通知...
  17. NGS测序嵌合体是个需要去除的错误扩增序列
  18. Mac系统如何开启任何来源
  19. 三维目标检测算法汇总学习笔记
  20. 大连文思海辉php面试题,文思海辉前端面试题

热门文章

  1. 可视化大屏设计尺寸_大屏数据可视化设计规律
  2. String赋值方式
  3. C++ 编译运行报错 error: stray ‘\200’ in program 解决方案
  4. kubernetes视频教程笔记 (23)-存储-Volume
  5. 陕西师范大学计算机专业录取,陕西师范大学计算机类专业2016年在湖北理科高考录取最低分数线...
  6. python3语法学习第四天--字符串
  7. es6 将字符串转换为json_ES6中Json、String、Map、Object之间的转换
  8. vue3 Vite 2.0 Vue-Router 4.0 TypeScript elementPlus admin 须弥戒后台案例小结
  9. 后台json返回给ajax,Ajax 如何 得到后台返回 的json数据,正确的格式应该如何去写?...
  10. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_11-webpack研究-npm和cnpm安装配置...