多线程操作ArrayList不安全解决方案

  • 1. 需求概述
  • 2. 需求验证
    • 2.1 测试方案
    • 2.2 验证结论
    • 2.3 代码实现
  • 3. 解决方案
    • 3.1 Vector
    • 3.1 Collections工具类
    • 3.1 CopyOnWriteArrayList

1. 需求概述

我们都知道List,ArrayList,以及Map,HashMap等常用的集合都是线程不安全的,替代及解决方案都是对应的current包下的对应的结合容器,比如hashMap对应CurrentHashMap,ArrayList对应什么呢,vector,也可以,就是效率太低,首选CopyOnWriteArrayList,读写分离,可重入锁效率更高。
以下就是测试验证以及原理分析。

2. 需求验证

2.1 测试方案

测试案例采用两种方式ArrayList与CopyOnWriteArrayList作为集合容器,同时开启多线程分别往两个容器内插入数据。

2.2 验证结论

最终结果是ArrayList数据丢失,而CopyOnWriteArrayList数据正常。

2.3 代码实现

package com.zrj.unit.collection;import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.SneakyThrows;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;/*** 多线程操作ArrayList** @author zrj* @since 2021/12/17**/
public class ThreadArrayList {// 自定义线程名称private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-%d").build();// 定义线程池private static ExecutorService pool = new ThreadPoolExecutor(30, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());/*** 多线程下ArrayList类线程不安全的解决方法及原理* 测试验证* 【simpleList】休眠30秒等待线程执行完成,理论长度6000,实际长度:5426* 【simpleCopyOnWriteList】休眠30秒等待线程执行完成,理论长度6000,实际长度:6000* 解决方案* 1.首选CopyOnWriteArrayList,读写分离,可重入锁。* 2.其次vector,synchronized效率低下,逐渐被遗弃。*/@SneakyThrowspublic static void main(String[] args) {//验证ArrayListList<String> simpleList = new ArrayList<>(100);//启动30个线程for (int i = 0; i < 30; i++) {pool.execute(() -> {//每个线程插入100条数据for (int j = 0; j < 100; j++) {simpleList.add("simpleList");}});}for (int i = 0; i < 30; i++) {pool.execute(() -> {//每个线程插入100条数据for (int j = 0; j < 100; j++) {simpleList.add("simpleList");}});}Thread.sleep(20000);System.out.println("【simpleList】休眠20秒等待线程执行完成,理论长度6000,实际长度:" + simpleList.size());//验证CopyOnWriteArrayListCopyOnWriteArrayList<String> simpleCopyOnWriteList = new CopyOnWriteArrayList<>();//启动30个线程for (int i = 0; i < 30; i++) {pool.execute(() -> {//每个线程插入100条数据for (int j = 0; j < 100; j++) {simpleCopyOnWriteList.add("simpleList");}});}for (int i = 0; i < 30; i++) {pool.execute(() -> {//每个线程插入100条数据for (int j = 0; j < 100; j++) {simpleCopyOnWriteList.add("simpleList");}});}Thread.sleep(20000);System.out.println("【simpleCopyOnWriteList】休眠20秒等待线程执行完成,理论长度6000,实际长度:" + simpleCopyOnWriteList.size());}
}

3. 解决方案

3.1 Vector

Vector类 是可以实现自动增长的对象数组,其add操作是用synchronized关键字修饰的,从而保证了add方法的线程安全。保证了数据的一致性,但由于加锁导致访问性能大大降低。
vector源码分析

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

3.1 Collections工具类

用Collections工具类将线程不安全的ArrayList类转换为线程安全的集合类。小体量数据的ArrayList类可以使用这种方法创建线程安全的类。

List<String> list=Collections.synchronizedList(new ArrayList);

3.1 CopyOnWriteArrayList

CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

public boolean add(E e) {//1、先加锁final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;//2、拷贝数组Object[] newElements = Arrays.copyOf(elements, len + 1);//3、将元素加入到新数组中newElements[len] = e;//4、将array引用指向到新数组setArray(newElements);return true;} finally {//5、解锁lock.unlock();}
}

多线程操作ArrayList不安全解决方案相关推荐

  1. C#多线程操作界面控件的解决方案

    C#中利用委托实现多线程跨线程操作 - 张小鱼 2010-10-22 08:38 在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常.这是微软为了 ...

  2. Android多线程操作操作对象出现空指针问题

    在android中经常会有一些多线程操作同一对象的问题,经常会发生空指针的情况,尤其是跑monkey测试时. 下面写点伪代码举例说明一下: //已知mHandler为成员变量: if (mHandle ...

  3. FMDatabaseQueue 数据库多线程操作、事务处理

    SQLite数据库多线程操作: 在上面一节中已经讲过FMDB的用法了,接下来讲讲sqlite在都线程中的用法.如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安 ...

  4. 一行 Python 实现并行化 -- 日常多线程操作的新思路 - 左手键盘,右手书 - SegmentFault...

    一行 Python 实现并行化 -- 日常多线程操作的新思路 - 左手键盘,右手书 - SegmentFault

  5. 多线程下ArrayList类线程不安全的解决方法及原理

    多线程下ArrayList类线程不安全的解决方法及原理 参考文章: (1)多线程下ArrayList类线程不安全的解决方法及原理 (2)https://www.cnblogs.com/fangting ...

  6. Shell多线程操作及线程数控制实例

    来源:http://www.jb51.net/article/51720.htm 这篇文章主要介绍了Shell多线程操作及线程数控制实例,文中从单线程实现一个需求开始,不断加入代码实现多线程以及线程数 ...

  7. python多线程读取数据库数据_python多线程操作MySQL数据库pymysql

    python多线程操作MySQL数据库pymysql 项目中使用多线程操作数据库提示错误:pymysql.err.InterfaceError: (0, "),原因是pymysql的exec ...

  8. MFC不能多线程操作控件的原因

    对于大多数mfc对象,请不要在线程间传递它们,不管是栈上的还是堆上的!原因如下:   mfc的大多数类不是线程安全的,调用传入对象的成员函数可能不会报错,但是未必能达到程序预定的功能!   mfc与界 ...

  9. python多线程读取数据库数据_Python基于多线程操作数据库相关知识点详解

    Python基于多线程操作数据库相关问题分析 本文实例分析了Python多线程操作数据库相关问题.分享给大家供大家参考,具体如下: python多线程并发操作数据库,会存在链接数据库超时.数据库连接丢 ...

最新文章

  1. 树莓派练习程序(蜂鸣器)
  2. 无人系统自主性研究综述
  3. 分布式缓存系统Memcached简介与实践(.NET memcached client library)
  4. voinc vue实现级联选择
  5. 大数据就业前景分析的太到位了【附:1T视频资料】
  6. linux中id命令的功能,Linux id命令参数及用法详解
  7. golang数据库的操作,更新删除增加单行查找与多行查找
  8. abortonerror_错误:无法解决:com.android.support:appcompat-v7:24.0.0
  9. 广州空气质量数据分析
  10. foobar2000的使用
  11. 面经分享:网友问我,怎样才能在谷歌匹兹堡办公室里写代码?上篇
  12. php获取qq头像和昵称,通过接口获取QQ头像和昵称
  13. 帧率FPS,屏幕刷新频率赫兹Hz
  14. 生鲜电商有哪些盈利模式?
  15. JMockit @mocked 注释标签
  16. 使用二手书App的心得
  17. MTK优美代码赏析2:MenuItemMask_flag
  18. 1323: 三角形判定
  19. 如何固定wifi direct的信道进行测试
  20. jsp简介及工作原理

热门文章

  1. Python使用selenium过天眼查滑块验证码反爬实现模拟登录
  2. IxChariot编辑脚本参数详解及配置
  3. 沉痛哀悼 | 上海交通大学张大兵教授不幸逝世,天妒英才!
  4. 《海思Hi35xx开发日记——之No.1》
  5. gzip chunked
  6. 微信小程序开发笔记 进阶篇②——多个微信小程序一个用户体系,同一个UnionID
  7. mysql实现生日倒计时
  8. 开始记录日常学习,2021年希望更进一步!
  9. 大小端模式的区别(即小尾和大尾的区别)
  10. Python零基础入门基础教程(非常详细)