JUC学习(五):ArrayList的线程安全问题分析与解决方案(vector、Collections、写时复制技术)_arraylist和vector的线程安全-程序员宅基地

技术标签: java  多线程  线程安全  juc  

目录

 一、异常演示

二、解决方案

        1、vector 

        2、Collections工具类 

        3、CopyOnWriteArrayList 写时复制技术

三、写时复制技术     

        1 、特性

        2、原理 


 一、异常演示

        循环创建线程,将数据放入集合的同时,从集合中读取数据。

/**
 * list集合线程不安全问题
 */
public class ThreadDemo04 {
    public static void main(String[] args) {

        List<String> list = new ArrayList<>();


        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                //向集合中添加内容
                list.add(UUID.randomUUID().toString().substring(0, 8));
                //从集合中获取内容
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

运行结果:

        出现了并发修改异常 

        那么如何解决呢?

二、解决方案

        1、vector 

        直接将ArrayList替换为Vector即可 

//        List<String> list = new ArrayList<>();
        List<String> list = new Vector<>();

         运行结果:

        为什么会这样呢?vector和ArrayList有什么不同呢?

        进入Vector的源码可以发现,里面几乎所有的方法都加了synchronized关键字

        这样确实可以避免线程安全问题,不过效率比较低。

       2、Collections工具类 

        使用Collections工具类中的synchronizedList()方法生成线程安全的集合。 

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

        运行结果:

         看一下jdk1.8的API对他的介绍:

        3、CopyOnWriteArrayList 写时复制技术

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

        运行结果:

三、写时复制技术     

        1 、特性

        它相当于线程安全的 ArrayList。和 ArrayList 一样,它是个可变数组;但是和 ArrayList 不同的时,它具有以下特性:

        1、它最适合于具有以下特征的应用程序:List 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
        2、 它是线程安全的。
        3、 因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销很大。
        4、 迭代器支持 hasNext(), next()等不可变操作,但不支持可变 remove()等操作。
        5、 使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。

        2、原理 

        写时复制技术中,读操作支持并发读,即多个线程可以同时读到集合内的元素。写操作是独立写,当一个写线程执行写操作时,所有其他写线程阻塞;当该线程写的时候,将原集合中的数据复制一份,在拷贝的集合中完成写操作后,再将该拷贝集合和原集合合并。

        为什么需要拷贝,在原数组直接修改不行吗?这篇文章讲得很清楚:CopyOnWriteArrayList写时复制的原理_Endwas的博客-程序员宅基地

        最后我们来看一下源码:

    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();
        }
    }

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_49499183/article/details/123630636

智能推荐

MyBatis-Plus实现多表联查(一对一,一对多使用)_mybatisplus一对多-程序员宅基地

文章浏览阅读3.8k次,点赞56次,收藏33次。在使用mybatis-plus开发需求的时候会发现对于大部分的业务场景来说都会使用到join来进行联表查询,但是mybatis-plus封装的 mapper 不支持 join,如果需要支持就需要自己手动去实现,给大家推荐一个好用的插件(Mybatis-Plus-Join(简称 MPJ)是一个 Mybatis-Plus的增强工具,在 MyBatis-Plus 的基础上只做增强不做改变,为简化开发、提高效率而生。_mybatisplus一对多

基于JAVA学生信息管理系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署-程序员宅基地

文章浏览阅读106次。基于JAVA学生信息管理系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署。springboot基于springboot和vue的酒店管理系统。springboot基于SpringBoot的自助旅游导航系统。springboot基于JSP的企业办公管理系统设计与实现。JSP宠物食品店系统的设计与实现sqlserver。ssm基于Java的幼儿早教系统软件的设计与实现。ssm基于vue的健康餐饮管理系统的设计与实现。ssm基于JAVA的求职招聘网站的设计与实现。

Nginx_Ubuntu-程序员宅基地

文章浏览阅读113次。一. 基本步骤  1.1环境准备    开始前,请确认gcc g++开发类库是否装好,默认已经安装。    注:等待linux下载更新功能准备好了 重启系统 在执行下载安装命令,如执行命令没有问题可以继续往下走      1. 最小Ubuntu安装插件      1. 需要安装        sudo apt-get install build-essen..._snail mock

Android逆向安全-无侵入找关键call之trace日志分析大法_安卓逆向的trace方法-程序员宅基地

文章浏览阅读2.9k次,点赞2次,收藏9次。标题找关键call是逆向的基本技能和分析目标,找到关键call后便可以进一步利用。在安卓App的逆向分析中,人肉逆向分析虽说不难,但是繁琐,特别是现在App体积动辄几十MB甚至几百MB,反编译出的jar或者smali文件相当多,找关键call无疑是大海捞针。那么有什么方法可以快速找关键call呢?之前介绍过两个方法:一个是插桩日志分析法,一个是借助加固的方法。插桩日志分析法,理解起来比较..._安卓逆向的trace方法

9个亮点助力你轻松建立emlog采集个人博客网站-程序员宅基地

文章浏览阅读604次。emlog采集是一款功能强大的博客管理系统,可以帮助你轻松搭建个人博客网站,分享你的思考和经验。无论你是新手还是老手,emlog采集都能满足你的需求,让你的博客更加专业和有吸引力。以下是emlog采集的9个亮点:1.简单易用emlog采集提供了简洁、直观的界面设计,使得操作变得轻松愉快。

Flutter 运行不了app:transformClassesWithMultidexlistForDebug错误!_app:transformclasseswithmultidexlistfordebug faile-程序员宅基地

文章浏览阅读1.5k次。Exit code 0 from: F:\Android\sdk\platform-tools\adb.exe -s emulator-5554 shell -x logcat -v time -t 1--------- beginning of mainWifiForwarder unable to open QEMU pipe: Invalid argumentexecuting: F..._app:transformclasseswithmultidexlistfordebug failed

随便推点

苹果手机测试网络速度的软件,‎App Store 上的“网速测试大师-测网速首选”-程序员宅基地

文章浏览阅读8.2k次。网速测试大师(SpeedTest Master)致力于为全球用户提供快速专业的网络测速服务。【最新功能】5G测速、Ping 测试、游戏Ping、一键设备检测。网速测试大师,是您的手机管家,wifi管家,随时随地的测速专家【全新工具】重磅推出史上最强工具箱:Ping测试,游戏Ping,跟踪路由。。。轻松解决任何网络问题【一键测速】只需30秒,快速、准确获得网速测试结果【全网测试】支持各大运营商测速;..._苹果手机测速软件

教了一年少儿编程,说说感想和体验-程序员宅基地

文章浏览阅读7.7k次,点赞24次,收藏115次。近两三年,少儿编程教育迅速崛起,成了 STEM 教育的主要代表。缘起少儿编程这个概念在国内兴起,总有个三四年了。2016 年,曾经有人问:“儿童学习编程是不是为了将来做'程序猿'?”。我当时给的回答是: 编程说白了就是用一种简单的符号语言描述一种解决方案来解决实际问题。编出程序的效果取决于两个方面:1、对于实际业务问题的了解;2、对算法和数据的掌控。 这两者的基..._python编程少儿课程课后评价

22东华大学计算机专硕854考研上岸实录-程序员宅基地

文章浏览阅读5.5k次,点赞21次,收藏72次。22东华大学计算机专硕854考研上岸实录注:本人所有学习笔记都在CSDN个人专栏(数学英语854数据库408等),这样方便个人复习,不用手写浪费时间,错题也是放在word文档中(题目、答案截图),方便纠错复习。(以上为本人所有考研纸质书籍,其他均为电子版资料。一般都是看电子版习题,答案写在演草纸上)一.2021年3~7月 数学第一轮、英语第一轮、408第一轮3月份的时候想报考上海大学,上海大学的专硕是22408,所以我开始着手准备起来。第一阶段我跟的是汤家凤的零基础课程(B站),老汤的确是一个很_东华大学计算机专硕

如何用《玉树芝兰》入门数据科学?-程序员宅基地

文章浏览阅读589次。链接起散落的文章,给《玉树芝兰》数据科学系列教程做个导读,帮你更为高效入门数据科学。(由于微信公众号外部链接的限制,文中的部分链接可能无法正确打开。如有需要,请点击文末的..._玉树芝兰深度学习优酷

macOS使用brew包管理器_brew清理缓存-程序员宅基地

文章浏览阅读2.1k次。macOS使用brew包管理器安装brewbrew权限修复brew常用命令Brew-cask相关命令brew serivces 相关命令brew 指南https://www.cnblogs.com/gee1k/p/10655037.html安装brew#- 该教程适用于macOS10.13以上版本#- 先安装XCode或者Command Line Tools for Xcode。Xcode可以从AppStore里下载安装,Command Line Tools for Xcode需要在终端中输入以下_brew清理缓存

【echarts没有刷新】用按钮切换echarts图表的时候,该消失的图表还在,加个key属性就解决了_echarts 怎么加key值-程序员宅基地

文章浏览阅读789次,点赞6次,收藏2次。【echarts没有刷新】用按钮切换echarts图表的时候,该消失的图表还在,加个key属性就解决了_echarts 怎么加key值

推荐文章

热门文章

相关标签