故障现象
出现 java.util.ConcurrentModificationException java的并发修改异常。
ArrayList<String> arrayList = new ArrayList<>(); for (int i = 0; i < 20; i++) { new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(list); }, String.valueOf(i)).start(); }
故障分析
ArrayList没有加锁。
并发争抢修改导致,查考我们的花名册签名情况。
一个人正在写入,另外一个同学过来抢夺,导致数据不一致异常。并发修改异常。
故障解决方案
3.1 new Vector<>();
3.2 Collection.synchronizedList(new ArrayList<>);
3.3 new CopyOnWriteArrayList<>()
优化建议(同样的错误不犯第二次)
笔记
写实复制CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前的容器Object[]添加,而是先将当前的容器Object[]进行copy
复制出一个新的容器Object[] newElements,然后新的容器Object[] newElements里添加元素,添加完,再将原容器的引用指向新的容器setArray(newElements);
这样做的好处时可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
所以CopyOnWrite容器也是一种读写分离的思想,都和写不同的容器
//出现并发修改异常 ArrayList<String> arrayList = new ArrayList<>(); // List<String> list = new Vector<String>(); // List<String> list = Collections.synchronizedList(new ArrayList<>()); List<String> list =new CopyOnWriteArrayList<>(); for (int i = 0; i < 20; i++) { new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(list); }, String.valueOf(i)).start(); } //其中 CopyOnWriteArrayList的add方法为如下 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(); }
同样CopyOnWriteArraySet也是线程不安全的。
而HashSet是否是安全的呢?
查看源码
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object();
其中利用了hashMap的key存储了值,而hashMap的value为一个固定的值new Object()。