Java并发编程之支持并发的list集合你知道吗
Java并发编程之-list集合的并发.
我们都知道Java集合类中的arrayList是线程不安全的。那么怎么证明是线程不安全的呢?怎么解决在并发环境下使用安全的list集合类呢?
本篇是《凯哥(凯哥Java:kagejava)并发编程学习》系列之《并发集合系列》教程的第一篇:
本文主要内容:怎么证明arrayList不是线程安全的?怎么解决这个问题?以及遇到问题解决的四个步骤及从源码来分析作者思路。
一:怎么证明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来模拟下文章开头签到例子。
司小司再签到的时候,先把签到表复制一份,然后再新的复制出来的签到表中进行签到。小明是原来签到表查看自己的信息的。这样就不会出现争强情况了。

Java并发编程之支持并发的list集合你知道吗的更多相关文章
- java并发编程--第一章并发编程的挑战
一.java并发编程的挑战 并发编程需要注意的问题: 并发编程的目的是让程序运行的更快,然而并不是启动更多的线程就能让程序最大限度的并发执行.若希望通过多线程并发让程序执行的更快,会受到如下问题的挑战 ...
- java并发编程与高并发解决方案
下面是我对java并发编程与高并发解决方案的学习总结: 1.并发编程的基础 2.线程安全—可见性和有序性 3.线程安全—原子性 4.安全发布对象—单例模式 5.不可变对象 6.线程封闭 7.线程不安全 ...
- Java并发编程系列-(1) 并发编程基础
1.并发编程基础 1.1 基本概念 CPU核心与线程数关系 Java中通过多线程的手段来实现并发,对于单处理器机器上来讲,宏观上的多线程并行执行是通过CPU的调度来实现的,微观上CPU在某个时刻只会运 ...
- 并发编程概述--C#并发编程经典实例
优秀软件的一个关键特征就是具有并发性.过去的几十年,我们可以进行并发编程,但是难度很大.以前,并发性软件的编写.调试和维护都很难,这导致很多开发人员为图省事放弃了并发编程.新版.NET 中的程序库和语 ...
- 【并发编程】Java对并发编程的支持历史
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 本文转载,原文请点击链接 本章主要对Java并发(Con ...
- 【Java并发编程】:并发新特性—Executor框架与线程池
Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocur ...
- Java并发编程实战笔记—— 并发编程1
1.如何创建并运行java线程 创建一个线程可以继承java的Thread类,或者实现Runnabe接口. public class thread { static class MyThread1 e ...
- Java并发编程实战 01并发编程的Bug源头
摘要 编写正确的并发程序对我来说是一件极其困难的事情,由于知识不足,只知道synchronized这个修饰符进行同步. 本文为学习极客时间:Java并发编程实战 01的总结,文章取图也是来自于该文章 ...
- 【Java并发编程】:并发新特性—障碍器CyclicBarrier
CyclicBarrier(又叫障碍器)同样是Java5中加入的新特性,使用时需要导入Java.util.concurrent.CylicBarrier.它适用于这样一种情况:你希望创建一组任务,它们 ...
随机推荐
- js对象或数组深复制
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 三星HTC价格跳水 安卓旗舰会否崩塌?
安卓旗舰会否崩塌?" title="三星HTC价格跳水 安卓旗舰会否崩塌?"> 官方降价,对于国产手机来说似乎是家常便饭.小米.魅族等,总会时隔几个月就将自家旗舰机 ...
- 机器学习迁移模型到IOS
https://paulswith.github.io/2018/02/24/%E8%BF%81%E7%A7%BB%E5%AD%A6%E4%B9%A0InceptionV3/ 上文记录了如何从一个别人 ...
- Seata-一站式分布式事务解决方案
Fescar 2019 年 1 月,阿里巴巴中间件团队发起了开源项目 Fescar(Fast & EaSy Commit And Rollback),和社区一起共建开源分布式事务解决方案. F ...
- Dangerous query method called with non-attribute argument(s)
踩坑 query method. 问题描述 现有model issue,需要对issues进行排序,根据指定的ID集合来决定记录的位置,比如id包含在(4, 6, 9)中的纪录就排在前面,剩下的排在后 ...
- linux Init分析(原创)
1.uboot的目标就是启动内核kernel: 2.kernel的目的就是启动应用程序,而第一个应用程序即是Init,构建根文件系统. 从uboot初始化配置后,引导内核的启动,启动函数为:start ...
- iPhone8的十面埋伏
不知不觉,iPhone已经走到了第十个年头,也正因如此,业界最普遍的预测就是:iPhone8会出现颠覆性创新,让人眼前一亮的同时,给苹果再度续命.平心而论,苹果早就青史留名,创造了大量的奇迹,科技 ...
- HTML中的<%%>是什么意思
背景: 今天在nutzwk框架中看到这段代码. 在index.html界面 <% layout("/layouts/platform.html"){ %> <di ...
- SGD与Adam识别MNIST数据集
几种常见的优化函数比较:https://blog.csdn.net/w113691/article/details/82631097 ''' 基于Adam识别MNIST数据集 ''' import t ...
- Mac中使用brew安装mysql
若不考虑版本直接执行以下命令 brew install mysql 若要选择版本只要加上@版本即可,例如 brew install mysql@5.7 安装完后启动mysql mysql.server ...