目录
一、集合类ArrayList线程不安全的代码示例
- 一、集合类ArrayList线程不安全的代码示例
- 二、集合类ArrayList线程不安全的故障现象
- 三、集合类ArrayList线程不安全的原因
- 四、集合类ArrayList线程不安全的解决方案
- 4.1、解决方式一:通过vector集合类解决(不建议)
- 4.2、解决方式二:通过Collections工具类解决
- 4.3、解决方式三:通过JUC包下的写时复制集合类解决
- 五、CopyOnWriteArrayList线程安全的源码解析
-
代码
import java.util.ArrayList; import java.util.UUID; /** * @description: ArrayList线程不安全的代码示例 * @author: xz */ public class ContainerNotSafe { public static void main(String[] args) { ArrayList list = new ArrayList(); //模拟10个线程,往ArrayList集合中添加数据 for(int i=1;i{ list.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(list); }).start(); } } }
-
输出结果如下:
- 报 java.util.ConcurrentModificationException 异常错误
- 并发争抢修改导致报 java.util.ConcurrentModificationException 异常错误。
-
代码
import java.util.*; /** * @description: 通过vector集合类解决集合类ArrayList线程不安全问题 * @author: xz */ public class ContainerNotSafe { public static void main(String[] args) { Vector list = new Vector(); //模拟10个线程,往Vector集合中添加数据 for(int i=1;i{ list.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(list); }).start(); } } }
-
输出结果如下:
-
不建议使用vector集合类解决的原因
(1)、Vector集合类于JDK1.0版本出现,Vector通过加锁的方式实现,保证了数据一致性,但是并发性下降。
(2)、ArrayList集合类于JDK1.2版本出现。ArrayList为了杜绝了Vector的情况,是一种不加锁的集合类,并发性加强,但是不保证线程的安全性。
-
代码
import java.util.*; /** * @description: 通过Collections工具类解决集合类ArrayList线程不安全问题 * @author: xz */ public class ContainerNotSafe { public static void main(String[] args) { List list=Collections.synchronizedList(new ArrayList()); //模拟10个线程,往synchronizedList集合中添加数据 for(int i=1;i{ list.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(list); }).start(); } } }
-
输出结果如下:
-
jdk1.8 API中的写时复制集合类截图如下:
-
代码
import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; /** * @description: 通过JUC包下的写时复制集合类解决ArrayList线程不安全问题 * @author: xz */ public class ContainerNotSafe { public static void main(String[] args) { List list=new CopyOnWriteArrayList(); //模拟10个线程,往ArrayList集合中添加数据 for(int i=1;i{ list.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(list); }).start(); } } }
-
输出结果如下:
-
源码如下
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(); } }
-
源码截图如下
-
【源码的理解】
-
写时复制 (copyOnWrite容器 )即写时复制的容器, 往容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[]进行copy 复制出一个新的object[] newElements ,然后向新容器object[] newElements 里面添加元素 ;
-
添加元素后再将原容器的引用指向新的容器 setArray(newElements);
-
这样的好处是可以对copyOnWrite容器进行并发的读,而不需要加锁, 因为当前容器不会添加任何容器。所以copyOnwrite容器也是一种读写分离的思想,读和写不同的容器。