Java并发编程之-list集合的并发.java
咱们都知道Java集合类中的arrayList是线程不安全的。那么怎么证实是线程不安全的呢?怎么解决在并发环境下使用安全的list集合类呢?编程
本篇是《凯哥(凯哥Java:kagejava)并发编程学习》系列之《并发集合系列》教程的第一篇:安全
本文主要内容:怎么证实arrayList不是线程安全的?怎么解决这个问题?以及遇到问题解决的四个步骤及从源码来分析做者思路。多线程
一:怎么证实arrayList在并发状况下是线程不安全的呢?建立一个list,用多个线程向list中添加数据。来看看结果并发
查看运行结果:ide
咱们发现了一个异常: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开发的同窗,能够参考成都Java培训班提供的学习大纲;