出现原因:在对集合迭代的过程中对集合进行一些修改(添加add,删除remove)的操作, 就会抛这个异常
//从数据库查询出符合条件的记录
List<NearbyshopSaleAPPDto> shopInfoByCbds = cbdMapper.selectShopByCBDCode(cbdCode);
//遍历集合
for (NearbyshopSaleAPPDto shopInfoByCbd : shopInfoByCbds) { //多家门店
BigDecimal firstSale = saleInfoByShopCodeAndYear(shopInfoByCbd.getShopCode(), yearList, 0); //第一年
shopInfoByCbd.setFirst(firstSale.toString());
//遍历集合时又给集合添加数据
shopInfoByCbds.add(shopInfoByCbd);
}
报错
java.util.ConcurrentModificationException: null
解决方案!!!!
我怕是敲代码敲傻了,这边将最后一个add删除就ok了。我的业务需要是修改list中的元素,而不是添加…已被自己蠢哭
瞎猫碰到死耗子,顺便巩固复习下出现这个bug的原因
一般 多线程情况下并发抢同一个资源类且没加锁 会出现这个现象
ArrayList是线程不安全的
一、故障现象
错误代码证明线程不安全
/**
* 集合类不安全,线程不安全
*/
private static void listNotSafe(){
List<String> list = new ArrayList<>();
for (int i = 0; i <= 30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
}
报错
二、解决方案
List<String> list = new Vector<>();
List<String> list = Collections.synchronizedList(new ArrayList<>());
三、优化建议
使用List<String> list = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList写时复制
源码
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();
}
}
Object[] newElements = Arrays.copyOf(elements, len + 1);//复制elements,指定长度为原长度+1
CopyOnWrite容器即写时复制的容器,往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行copy,复制出一个新的容器Object[] newElementsnewElements[len] = e;
然后向新的容器Object[] newElements里添加元素setArray(newElements);
添加完元素后,再将原容器的引用指向新容器 setArray(newElements);这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁。因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器