- 并发修改(ConcurrentModificationException)异常问题分析?
public class ContainerNotSafeDemo {
public static void main(String[] args) {
listNotSafe();
}
private static void listNotSafe() {
List<String> list=new ArrayList<>();
for (int i=1;i<=30;i++){
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},"AA").start();
}
}
运行结果:
......
0c2be7f9, d866ffc4, ea022d39, 6b163bf3, 358fc15f, fae59c18, cf845fb5, 56bdcf45, 1c868d45, a424009e, fe2f365a, adf1965c, 79ac4944, 3e5b3f02, 0546778e, 341ee51d, 6341c0b3, 3f2f65aa, 9d44af9e, 85a1f6a0, f0e0197e, 700b0baa]
Exception in thread "AA" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
.......
ArrayList线程不安全,多线程对list进行并发修改时,底层add()方法并未加锁,因此会导致并发修改异常
//ArrayList的add()方法源码
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
- 解决方法 修改List实现,下面三种
List<String> list=new Vector<>(); //解决方法1,效率低
List<String> list= Collections.synchronizedList(new ArrayList<>()); //解决方法2
List<String> list=new CopyOnWriteArrayList<>(); //解决方法3 写时复制==>读写分离的思想
- 着重看第三种: 集合类不安全之写时复制 CopyOnWriteArrayList
- 往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行Copy,复制一个新的容器Object[] newElements,然后新的容器Object[] newElements里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElements);
- 好处:可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素,所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器
private transient volatile Object[] array; //底层数组volatile修饰
final Object[] getArray() {
return array;
}
....
//源码分析
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); //拷贝当前容器
Object[],扩容一个
newElements[len] = e; //新的容器Object[] newElements里添加元素
setArray(newElements); //原容器的引用指向新的容器
return true;
} finally {
lock.unlock();
}
}
.....