从属性文件读取时java.util.ConcurrentModificationException

时间:2018-10-23 07:36:43

标签: java multithreading properties log4j

由于在某些环境中重新启动JVM之后得到System.getProperties(),我无法使用java.util.ConcurrentModificationException读取JVM配置属性。

  

[err] java.util.ConcurrentModificationException   [err] at java.util.Hashtable $ Enumerator.next(Hashtable.java:1502)

我必须多次重启VM,以避免前面提到的错误。

我到目前为止所做的:

  • 同步了将属性键和值读取并写入日志文件的方法;
  • 因为Java的Properties对象是一个HashMap,所以我尝试使用同步Map;
  • 我试图通过使用更多共享相同Properties对象的线程来模拟并发问题,但是我无法在本地环境中重现该错误;
  • 由于线程安全,我正在使用StringBuffer;

    private static final Logger LOG = LoggerFactory.getLogger(PropertyLogger.class);
    public static synchronized final void logProperties() {
            Level oldLevel = LOG.getLevel();
            LOG.setLevel(Level.INFO);
            Properties props = System.getProperties();
            Map<Object, Object> shared = Collections.synchronizedMap(new HashMap<>());
            shared.putAll(props);
    
            for (final Entry<Object, Object> entry : shared.entrySet()) {
              try{  StringBuffer buffer = new StringBuffer();
                buffer.append(entry.getKey());
                buffer.append(" = "); //$NON-NLS-1$
                buffer.append(entry.getValue());
                LOG.info(buffer.toString());
              }
              catch (Exception ex){
                  ex.printStackTrace();
              }
            }
            LOG.setLevel(oldLevel);
    
        }
    

我可能正在处理的问题也由用于写入的log4j库触发了,这是我所知的线程安全性。

我添加了堆栈跟踪:

  

[err] java.util.ConcurrentModificationException [err]在   java.util.Hashtable $ Enumerator.next(Hashtable.java:1502)[err]在   com.myapp.common.PropertyLogger.logProperties(PropertyLogger.java:23)   [err] at   com.myapp.input.ConfigurationServer.parse(ConfigurationServer.java:710)   [err] at   com.myapp.input.ConfigurationServer.configure(ConfigurationServer.java:94)   com.myapp.input.Application.run(Application.java:78)的[err]   com.myapp.input.servlet.InputStarter $ ValidatorThread.run(InputStarter.java:113)

此致

PS:我应该添加同步块来调用该方法吗? 例如:在parse方法中,应使用

调用我的代码
synchronized(this) {
     PropertyLogger.logProperties();
}

1 个答案:

答案 0 :(得分:1)

问题不在于日志记录框架,而是行

shared.putAll(props);

Properties类扩展了Hashtable,并且系统属性可以随时更改。使用shared.putAll(props)遍历props类的对象Properties(Hashtable),如果在迭代过程中修改了任何值,我们将得到此错误ConcurrentModificationException

一种解决方案是在迭代之前在System.Properties()对象上调用clone()