并发修改例外

时间:2012-05-18 19:13:35

标签: java multithreading concurrency

我在此方法上获得以下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?

4 个答案:

答案 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方法的一致性。对于其余部分,您需要进行客户端同步