代码编织梦想

Java并发编程之-list集合的并发.

我们都知道Java集合类中的arrayList是线程不安全的。那么怎么证明是线程不安全的呢?怎么解决在并发环境下使用安全的list集合类呢?

本篇是《凯哥(凯哥Java:kagejava)并发编程学习》系列之《并发集合系列》教程的第一篇:

本文主要内容:怎么证明arrayList不是线程安全的?怎么解决这个问题?以及遇到问题解决的四个步骤及从源码来分析作者思路。

目录

一:怎么证明arrayList在并发情况下是线程不安全的呢?

java.util.ConcurrentModificationException是什么

二:怎么解决这个问题

1:怎么操作导致的故障及现象是什么?

2:分析产生这个问题的原因

3:解决方案是什么?

1:使用线程安全的List的子类Vectory

2:使用collections工具类的sync方法

4:解决方案可以优化吗?优化的建议是什么?


一:怎么证明arrayList在并发情况下是线程不安全的呢?

创建一个list,用多个线程向list中添加数据。来看看结果

 

查看运行结果:

 

我们发现了一个异常:java.util.ConcurrentModificationException

java.util.ConcurrentModificationException是什么

这个异常什么意思呢?我们来看看这个异常源码中类的注释信息:

 

This exception may be thrown by methods that have detected concurrent(此异常可能由检测到并发的方法引发).

一般可以理解为,这是并发导致的异常。那么在并发情况下出现了异常。是不是从侧面说明arrayList是不安全的呢?

二:怎么解决这个问题

这里凯哥顺便说下,解决问题的一般步骤。

1:怎么操作导致的故障及现象是什么?

操作:多个线程对list进行add添加操作的时候

结果:抛出了java.util.ConcurrentModificationException异常信息

2:分析产生这个问题的原因

举个现实生活中的例子。签到表,这个大家都见过吧,应该都签到过吧。比如现在有个会议很多人来参与,需要签到。现在,司小司正在签到表上写自己的名字时候,小明非要看签到表上面有没有自己名字。因为司小司正在签到进行中,小明硬是要查看,把签到表抢过去,结果就是签到表被撕坏了或者是司小司的笔在签到表上留下了长长的痕迹。如果上面这个例子用计算机角度分析的话。

两个线程(司小司和小明)对一个共享变量(签到表,可以理解为是人名的集合)进行读写操作(司小司签到是写操作,小明要查看自己是否签到了,可以理解为读操作),因为两个线程都来竞争共享资源。后果就是签到表被撕坏了或者是司小司的笔在签到表上留下了长长的痕迹。异常现象。用到上面我们多个线程对list进行操作的时候,就抛异常了多线程并发修改异常信息。

3:解决方案是什么?

1:使用线程安全的List的子类Vectory

List list = new Vectory();

查看vectory的add方法源码:

 

发现,原来vector的add方法是加的并发锁来保证线程安全的

2:使用collections工具类的sync方法

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

查看源码:

 

 

原来都是synchronized的。

我们在来看看synchronizedList方法上面的注释。

 

发现,原来源码中是把整个list对象作为同步锁的锁。这样来保证线程安全的

4:解决方案可以优化吗?优化的建议是什么?

我们知道synchronized关键字是同步锁机制。强制并行转化成串行的一种方案。这种对性能消耗比较大。有没有更其他可以优化的方案吗?

来看看使用JUC并发包下的:CopyOnWriteArrayList(写时复制list)来解决吧。

先来看看这个类的add方法的源码:

 

从源码中,我们可以看到复制了一个新的list集合,将新元素在新集合中操作。那么为什么这种操作就不会出现并发异常呢?

因为这种思想,可以理解为读写分离的思想。因为get还是使用原来list的get的方法。写的时候,在复制一份原来的,然后再复制出来的基础上进行修改的。那么怎么保证数据问题呢?我们从源码中可以看到使用到了ReentrantLock(关于锁相关的。凯哥(凯哥Java:kaigejava)将在后面详细的讲解的)锁来控制的。

那么现在使用CopyOnWriteArrayList来模拟下文章开头签到例子。

司小司再签到的时候,先把签到表复制一份,然后再新的复制出来的签到表中进行签到。小明是原来签到表查看自己的信息的。这样就不会出现争强情况了。

 

 

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

每日一题:LeetCode之子集-爱代码爱编程

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 说明:解集不能包含重复的子集。 示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] 思路:回溯算法,以例子为例,每个位置都会出现1,2,3三种数字,那么每一层就是一个

剑指offer试题编程练习19(java) 顺时针打印矩阵中的元素-爱代码爱编程

19、输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. 4*4的矩阵为: 1   2   3   4 5   6   7   8

Web应用程序设计笔记1.1_web前端、后端、全栈分别是做什么的?-爱代码爱编程

Web应用程序设计笔记1.1-web前端、后端、全栈分别是做什么的? 一、Web前端开发工程师 前端开发工程师是Web前端开发工程师的简称。前端开发,就是要创造上面提到的网站面向用户的部分背后代码,并通过建立框架,构建沉浸性的用户体验。为了实现这个目标,开发需要熟练运用下列语言、框架、工具库; 三大语言:HTML、CSS和JavaScript此外,掌

Windows下MongoDB配置,以及用navcat导入数据库-爱代码爱编程

Windows下MongoDB配置,以及用navcat导入数据库 下载需要工具 在网站:https://www.mongodb.com/download-center/community下载需要的版本。 可以选择安装版,也可以使用ZIP    压缩版。个人建议直接使用压缩版。   下载下载来解压到磁盘中 配置需要的目录      解压后的

使用二分法查找一个数组中的数值和索引-爱代码爱编程

使用二分法查找一个数组中的数值和索引 内附 插入排序! public static void main(String[] args) { // 定义一个无序数组; int[] arr= {12,25,1,10,45,56,15,75,9,10,48,60,11}; // 调用method方法进行排序; method(arr);

线程安全性原理分析---Lock(让你明白彻底AQS实现原理)-爱代码爱编程

ReentrantLock 的实现原理 结合上篇《Lock基础分析》那么我们接下来分析下它的实现原理。我们知道锁的基本原理是:基于将多线程并行任务通过某一种机制实现线程的串行执行,从而达到线程安全性的目的。在 synchronized 中,我们分析了偏向锁、轻量级锁、乐观锁。基于乐观锁以及自旋锁来优化了 synchronized 的加锁开销,同时在重量级

趣学Spring:一文搞懂Aware、异步编程、计划任务-爱代码爱编程

你好呀,我是沉默王二,一个和黄家驹一样身高,刘德华一样颜值的程序员(不信围观朋友圈呗)。从 2 位偶像的年纪上,你就可以断定我的码龄至少在 10 年以上,但实话实说,我一直坚信自己只有 18 岁,因为好学使我年轻。本篇文章就打算通过我和三妹对话的形式来聊一聊“Spring 的 Aware、异步编程、计划任务”。 教妹学 Spring,没见过这么放肆的标题

java零基础教学------变量-爱代码爱编程

更多免费内容,点击了解:https://how2j.cn/k/variable/variable-tutorial/258.html 目录 变量系列教材 (一)- Java中 什么是变量 步骤 1 : 什么是变量 变量系列教材 (二)- Java中有八种基本变量类型 示例 1 : 整型 示例 2 : 字符型 示例 3 : 浮点型 示例 4 

函数-爱代码爱编程

函数 函数是什么? 维基百科中对函数的定义:子程序 在计算机科学中,子程序是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而相较于其他代码,具备相对的独立性。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。C语言中函数的分类: 1.库函数 2.自定义函数 库函数 为什么会有库函

授人以鱼不如授人以渔,一文让你了解Python的所有内置函数用法-爱代码爱编程

大家知道Python一共有多少个内置函数吗? 答案是:一直在变,所以当下有多少不确定! 那我们可以手动来查看一下,打开 IDLE,输入 dir(__builtins__) 即可: >>> dir_list = dir(__builtins__) >>> len(dir_list) 153 看来目前有 153

学习笔记(01):C#急速入门-Main方法,语句,块和关键字-爱代码爱编程

立即学习:https://edu.csdn.net/course/play/20589/257713?utm_source=blogtoedu Main方法:每个项目有且必须只有一个Main方法(函数),它是程序的入口,其格式如下: static void Main (string [] args) {        语句块; }   语句:

【0 基础学 Java】(四)运算符-爱代码爱编程

【0 基础学 Java】(四)运算符 码字不易,对你有帮助 点赞/转发/关注 支持一下作者 微信搜公众号:不会编程的程序圆 看更多干货,获取第一时间更新 思维导图 目录 文章目录 【0 基础学 Java】(四)运算符思维导图目录正文前言一 运算符1. 算术运算符2. 关系运算符3. 逻辑运算符逻辑与 &&