consul配置修改刷新触发的java.util.ConcurrentModificationException异常 | 您所在的位置:网站首页 › util包下有哪些类 › consul配置修改刷新触发的java.util.ConcurrentModificationException异常 |
遇到的问题
项目中用到consul作为配置中心,在修改consul配置时,会发现服务报出集合类修改异常: java.util.ConcurrentModificationException at java.util.ArrayList.forEach(ArrayList.java:1260) 问题分析Java1.8 // ArrayList 部分源码 public void forEach(Consumer action) { Objects.requireNonNull(action); final int expectedModCount = modCount; @SuppressWarnings("unchecked") final E[] elementData = (E[]) this.elementData; final int size = this.size; for (int i=0; modCount == expectedModCount && i // 此处抛出异常 (line: 1260) throw new ConcurrentModificationException(); } }一开始并不能确定是consul配置刷新导致的。经过试验和跟踪,发现确实在修改consul配置时,正在使用集合类型的配置项导致的。 复现方法如下: consul中的配置 # consul中配置 testKeys: - a - b - c - d - e public static void main(String[] args) { ConfProperties p = ctx.getBean(ConfProperties.class); List list = p.getTestKeys(); System.out.println(list.hashCode()); System.out.println(list.size()); list.forEach( k -> { System.out.println(k); try { Thread.sleep(20000L); } catch (InterruptedException e) { throw new RuntimeException(e); } }); System.out.println(list.hashCode()); System.out.println(list.size()); } @Configuration @Data public calss ConfProperties { private List testKeys; }在运行过程中,去修改consul配置,会看到异常抛出。也就是ArrayList的modCount发生了改动;具体经过debug跟踪是spring cloud 组件实现的动态配置刷新中对集合类的配置更新使用了合并操作: 具体代码位于CollectionBinder.merge方法中 //org.springframework.boot.context.properties.bind.CollectionBinder#merge try { existingCollection.clear(); existingCollection.addAll(additional); return this.copyIfPossible(existingCollection); } catch (UnsupportedOperationException var5) { return this.createNewCollection(additional); }addAll 修改了原集合,modCount也会随之修改。 解决方法一种比较简单的解决办法是在每次获取集合类配置时,拷贝出一个新的集合,避免引用集合被修改; @Configuration @Data public calss ConfProperties { private List testKeys; public List getTestKeys() { return testKeys != null ? new ArrayList(testKeys) : Collections.emptyList(); } } |
CopyRight 2018-2019 实验室设备网 版权所有 |