同事新一项目,大概率启动出现
ConcurrentModificationException
他自己研究认为是
archaius 包冲突导致
直接把包给排除干掉
因为其他项目都是一样的依赖包,感觉问题的根源不在这,而且把这个包去掉可能会影响项目的其他功能(配置刷新)
排查的第一步还是看报错信息,报错是在HashTable里面的next方法。
大致的报错原因是因为HashTable对象中的modCount值与其迭代器快照中的值不同,简单来说就是在获取迭代器后,又对源HashTable做了修改
初看,应该是一个并发问题没跑了
接着通过断点的方式,找到了其时间范围前后对系统属性做了设置的地方(因为获取迭代器的地方,包装的就是系统属性的)
找到了两个地方
第一个地方就是同事认为有问题的
archaius
包中的
ArchaiusAutoConfiguration
protected static void configureArchaius( ConfigurableEnvironmentConfiguration envConfig, ConfigurableEnvironment env, List<AbstractConfiguration> externalConfigurations) { if (initialized.compareAndSet(false, true)) { String appName = env.getProperty("spring.application.name"); if (appName == null) { appName = "application"; log.warn("No spring.application.name found, defaulting to 'application'"); } System.setProperty(DeploymentContext.ContextKey.appId.getKey(), appName); ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration(); // support to add other Configurations (Jdbc, DynamoDb, Zookeeper, jclouds, // etc...) if (externalConfigurations != null) { for (AbstractConfiguration externalConfig : externalConfigurations) { config.addConfiguration(externalConfig); } } config.addConfiguration(envConfig, ConfigurableEnvironmentConfiguration.class.getSimpleName()); defaultURLConfig = new DynamicURLConfiguration(); try { config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME); } catch (Throwable ex) { log.error("Cannot create config from " + defaultURLConfig, ex); } // TODO: sys/env above urls? if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) { SystemConfiguration sysConfig = new SystemConfiguration(); config.addConfiguration(sysConfig, SYS_CONFIG_NAME); } if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) { EnvironmentConfiguration environmentConfiguration = new EnvironmentConfiguration(); config.addConfiguration(environmentConfiguration, ENV_CONFIG_NAME); } ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration(); config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES); config.setContainerConfigurationIndex( config.getIndexOfConfiguration(appOverrideConfig)); addArchaiusConfiguration(config); } else { // TODO: reinstall ConfigurationManager log.warn( "Netflix ConfigurationManager has already been installed, unable to re-install"); } }
初始化的时候设置了@appId的系统属性
第二个地方是
NioEventLoop
static { String key = "sun.nio.ch.bugLevel"; String bugLevel = SystemPropertyUtil.get("sun.nio.ch.bugLevel"); if (bugLevel == null) { try { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { System.setProperty("sun.nio.ch.bugLevel", ""); return null; } }); } catch (SecurityException var3) { logger.debug("Unable to get/set System Property: sun.nio.ch.bugLevel", var3); } } int selectorAutoRebuildThreshold = SystemPropertyUtil.getInt("io.netty.selectorAutoRebuildThreshold", 512); if (selectorAutoRebuildThreshold < 3) { selectorAutoRebuildThreshold = 0; } SELECTOR_AUTO_REBUILD_THRESHOLD = selectorAutoRebuildThreshold; if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.noKeySetOptimization: {}", DISABLE_KEY_SET_OPTIMIZATION); logger.debug("-Dio.netty.selectorAutoRebuildThreshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD); } }
最后通过设置默认的
sun.nio.ch.bugLevel系统属性
暂时解决了这个问题