List集合多线程并发

  • 前言
  • 一、List集合使用模拟并发测试
    • 1.1 单线程环境下
    • 1.2 多线程环境下
  • 二、解决方案
    • 2.1 使用Vector类
    • 2.1 使用Collections.synchronizedList
    • 2.3 使用并发容器CopyOnWriteArrayList
  • 总结

前言

在日常开发过程中,List是我们常用的集合,比如查询数据库内容返回值比会用一个集合来装,但是在多线程并发的条件下,会出现安全问题吗?下面我们就来测试一下,如果出现安全问题,该如何解决.

一、List集合使用模拟并发测试

1.1 单线程环境下

public static void main(String[] args) {// List集合List<String> list = new ArrayList<>();// 循环插入for (int i = 0; i < 10; i++) {list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);}
}


可以看到单线程条件下,我们做list的插入操作完全没问题,下面我们来模拟并发条件下执行,会出现什么问题。

1.2 多线程环境下

public static void main(String[] args) {// List集合List<String> list = new ArrayList<>();// 循环插入for (int i = 0; i < 10; i++) {// 开启线程执行new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);},"线程List").start();}
}

ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常,就是并发修改异常。

二、解决方案

2.1 使用Vector类

public static void main(String[] args) {// List集合List<String> list = new Vector<>();// 循环插入for (int i = 0; i < 10; i++) {// 开启线程执行new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);},"线程List").start();}
}

Vector 是同步访问的,它的add方法底层加了synchronized关键字修饰。

测试结果:

2.1 使用Collections.synchronizedList

public static void main(String[] args) {// List集合List<String> list = Collections.synchronizedList(new ArrayList<>());// 循环插入for (int i = 0; i < 10; i++) {// 开启线程执行new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);},"线程List").start();}
}

查看底层源码可以发现他也使用了synchronized关键字修饰。

2.3 使用并发容器CopyOnWriteArrayList

public static void main(String[] args) {// List集合List<String> list = new CopyOnWriteArrayList<>();// 循环插入for (int i = 0; i < 10; i++) {// 开启线程执行new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);},"线程List").start();}
}

查看源码它使用的是lock锁机制。

写入时复制,有多个线程调用的时候,写入的时候,复制一份,避免覆盖造成数据问题。就是在写的时候不对原集合进行修改,而是重新复制一份,修改完之后,再移动指针。

从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。

解读源码:

/*** Appends the specified element to the end of this list.** @param e element to be appended to this list* @return {@code true} (as specified by {@link Collection#add})*/
public boolean add(E e) {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();//解锁}
}

add()在添加集合的时候加上了锁,保证了同步,避免了多线程写的时候会Copy出N个副本出来。

总结

CopyOnWriteArrayList使用场景:读多写少(白名单,黑名单,商品类目的访问和更新场景),集合不大。所以一般来说,我们都会使用JUC包下给我们提供的线程安全容器,而不是使用老一代的线程安全容器。

List集合多线程并发条件下不安全,如何解决?相关推荐

  1. MySQL 在并发场景下的问题及解决思路

    1.背景 对于数据库系统来说在多用户并发条件下提高并发性的同时又要保证数据的一致性一直是数据库系统追求的目标,既要满足大量并发访问的需求又必须保证在此条件下数据的安全,为了满足这一目标大多数数据库通过 ...

  2. MySQL在并发场景下的问题及解决思路

    MySQL在并发场景下的问题及解决思路 参考文章: (1)MySQL在并发场景下的问题及解决思路 (2)https://www.cnblogs.com/leefreeman/p/8286550.htm ...

  3. Redis高并发场景下秒杀超卖解决

    目录 1 什么是秒杀 2 为什么要防止超卖 3 单体架构常规秒杀 3.1 常规减库存代码 3.2 模拟高并发 3.3 超卖现象 3.4 分析原因 4 简单实现悲观乐观锁解决单体架构超卖 4.1 悲观锁 ...

  4. Java中的同步集合与并发集合有什么区别?

    同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高. 在Java1.5之前程序员们只有同步集合来用且在多线程并发的时候会导致争用,阻碍了系统的扩展性.Java5介 ...

  5. 并发场景下MySQL存在的问题及解决思路

    转载自 并发场景下MySQL存在的问题及解决思路 目录 1.背景 2.表锁导致的慢查询的问题 3.线上修改表结构有哪些风险? 4.一个死锁问题的分析 5.锁等待问题的分析 6.小结 一.背景 对于数据 ...

  6. 《多线程并发任务处理组件》序章——生活不能就这样悲泣

    背景 入行也有些日子, 最近突然心中迸发出一个想法, 想要去解决多线程并发环境的一些问题. 并不是说现在社区找不到优秀的这方面的开源项目, 更多的是想自己动手做一些东西出来, 毕竟性格一直在驱使着我要 ...

  7. 对Java多线程编程的初步了解,实现多线程的三种方式以及多线程并发安全的线程同步机制

    什么叫进程?什么叫线程? 进程相当于一个应用程序,线程就是进程中的一个应用场景或者说是一个执行单元,一个进程可以启动多个线程,每个线程执行不同的任务,一个线程不能单独存在,他必须是进程的一部分,当进程 ...

  8. 无锁编程[0]__多线程条件下的计数器__原子的加/减/与/或/异或操作__sync_fetch_and_add,__sync_add_and_fetch等

    多线程条件下的计数器是服务器开发的常用操作,比如异步请求sessionid的活动,通常我们会用: 1.加锁取sessionid 2.分段取sessionid (在初始化阶段完成多线程分段取sessio ...

  9. 转Linux多线程条件下的计数器 2011-11-15 00:00中国IT实验室佚名

    Linux多线程条件下的计数器 2011-11-15 00:00中国IT实验室佚名 字号:A+|A- 最近编码需要实现多线程环境下的计数器操作,统计相关事件的次数.下面是一些学习心得和体会.不敢妄称原 ...

最新文章

  1. crowd counting_[Crowd_Counting]-PGCNet-ICCV2019
  2. python使用什么注释语句和运算-python 闯关之路一(语法基础)
  3. 故障排除:硬盘坏道修复术
  4. vb 字符串替换_学习VB编程第69天 字符串查找与替换
  5. ACL 2020 | MobileBERT:一种与任务无关的模型压缩方法
  6. 01: 实现注册登录功能
  7. linux线程池简单实例
  8. 【数据挖掘】数据挖掘和数据分析基础
  9. 小米崔宝秋:小米 AIoT 深度拥抱开源
  10. 启动程序端口被占用Address already in use: bind解决方案
  11. python集合特点和注意事项_Python:list 和 array的对比以及转换时的注意事项
  12. java简易计算器程序框图_简易计算器程序设计思路及流程图
  13. MLCDForest:用深度森林对长链非编码RNA进行疾病预测的多标签分类模型
  14. 常用的第三方ui框架
  15. 虚拟网卡服务器端软件,不再挤房间!自己动手架设自己的“浩方”对战平台
  16. 11个并不广为人知,但值得了解的Python库
  17. IDempiere介绍
  18. WebDAV之葫芦儿·派盘 + CloudBeats
  19. java基础(个人笔记)
  20. php支持连接sql server数据库

热门文章

  1. 信息学奥赛一本通 1137:加密的病历单 | OpenJudge NOI 1.7 12
  2. 信息学奥赛一本通(1260:【例9.4】拦截导弹(Noip1999))
  3. 信息学奥赛C++语言:统计数字字符个数
  4. 信息学奥赛一本通C++语言——1007:计算(a+b)×c的值
  5. proteus里面没有stm32怎么办_使用C#编写STM32对接物联网平台IoTSharp发送遥测数据
  6. DenseNet简单总结
  7. python selenium_自动化测试:Selenium+Python环境搭建
  8. uds帧格式_UDS诊断帧
  9. 生成对抗网络(GAN)的发展史
  10. python网络框架生产环境_配置Django框架为生产环境的注意事项(DEBUG=False)