一、常规的集合在并发的情况下是不安全的
上代码:
public class ListTest01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,7));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
上面的代码在测试类中运行,控制台打印结果:
报并发修改异常!!!!!!
Exception in thread "2" Exception in thread "4" Exception in thread "7"
java.util.ConcurrentModificationException
二、解决不安全的方案
方案1:把普通的list集合换成Vector集合,他在java中是安全的
控制台打印结果:
方案2:所有集合的顶部有一个Collections工具类,里面有给普通List集合上锁的方法
public class ListTest01 {
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,7));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
方案3:JUC中提供了一个CopyOnWriteArrayList
写入时复制,简称COW,计算机程序设计领域的一种优化策略,当有多个线程调用的时候,list是唯一的,读取的是固定的,写入的时候可能存在覆盖前一个人写的内容,那么现在就可以先将原本的内容复制一份,执行插入等操作,然后在将新的数据插入回去,保证线程的安全的类
使用方法:
public class ListTest01 {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,7));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
控制台打印结果:
成功解决了并发修改异常的问题
拓展下:为什么CopyOnWriteArrayList比Vector好?
在Vector底层中,对于集合add的方法是加了synchroied锁,而我们一致认为synchroied锁是效率低的
而最新的CopyOnWriteArrayList底层的add方法,是加了Lock锁,效率比synchroied锁要高