我在此方法上获得以下java.util.ConcurrentModificationException
private AtomicReference<HashMap<String, Logger>> transactionLoggerMap = new AtomicReference<HashMap<String,Logger>>();
public void rolloutFile() {
// Get all the loggers and fire a temp log line.
Set<String> transactionLoggerSet = (Set<String>) transactionLoggerMap.get().keySet();
Iterator<String> transactionLoggerSetIter = transactionLoggerSet.iterator();
while(transactionLoggerSetIter.hasNext()){
String key = (String) transactionLoggerSetIter.next();
Logger txnLogger = transactionLoggerMap.get().get(key);
localLogger.trace("About to do timer task rollover:");
txnLogger.info(DataTransformerConstants.IGNORE_MESSAGE);
}
}
请建议,如果我使用原子参考,我如何获得como?
答案 0 :(得分:9)
ConcurrentModificationException
表示您已在迭代器之外修改了集合。我没有看到你的循环中的任何修改,所以我假设还有另一个线程也在你迭代它的同时在transactionLoggerMap
中添加或删除。
即使你将它包装在AtomicReference
中,你仍然不能让两个线程同时对同一个非同步集合进行更改。 AtomicReference
不同步它正在包装的对象 - 它只是为您提供了一种原子获取和设置该引用的方法。
您需要使用ConcurrentHashMap
课程或使用HashMap
方法包裹Collections.synchronizedMap(map)
来使其成为同步集合。
答案 1 :(得分:1)
因为您在迭代期间无法防止并发修改。原子参考仅确保您获得地图(及其内容)。
答案 2 :(得分:1)
也许您可以考虑迭代集合的本地副本而不是相同的集合。这将是一种简单的方法,可确保您在循环时不会修改您的收藏。建议在多线程环境中使用不可变对象,并免费防止此类问题。
希望它有所帮助。
答案 3 :(得分:0)
删除多余的
Set<String> transactionLoggerSet = (Set<String>) transactionLoggerMap.get().keySet();
在迭代地图时,您仍然必须使用同步。 SynchronizedMap保证其API方法的一致性。对于其余部分,您需要进行客户端同步