2012-05-18 67 views
2

我得到這個方法併發修改例外

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); 
    } 
} 

請建議,如果我使用一個原子參考以下java.util.ConcurrentModificationException,我如何得到一個科莫?

回答

1

因爲您在迭代期間無法防止併發修改。原子參考只能確保你得到你的地圖(和它的內容)。

9

A ConcurrentModificationException意味着您已經修改了迭代器之外的集合。我沒有看到你的循環中有任何修改,所以我認爲還有另一個線程在你迭代它的同時也添加或刪除了transactionLoggerMap

即使您將它封裝在AtomicReference中,仍不能讓兩個線程同時對相同的非同步集合進行更改。 AtomicReference確實不是同步它包裝的對象 - 它只是給你一個方法來自動獲取和設置該引用。

您需要通過使用ConcurrentHashMap類或使用Collections.synchronizedMap(map)方法包裝HashMap來使其成爲同步收集。

+0

這是完全正確的,但在這個特定問題的上下文中可能是錯誤的,因爲'get'調用可能會改變地圖的結構。更多在這裏:http://goo.gl/f3faP – rtheunissen

+0

OP正在討論一個'HashMap',它不是一個訪問有序映射@paranoid,而是一個好點。 – Gray

1

也許你可以考慮迭代集合的本地副本而不是相同的集合。這將是一種簡單的方法,可以確保您的收藏集在循環播放時不會被修改。建議在多線程環境中使用不可變對象,並免費解決這類問題。

希望它有幫助。

0

刪除冗餘 Set<String> transactionLoggerSet = (Set<String>) transactionLoggerMap.get().keySet(); 您在迭代地圖時仍然必須使用同步。 SynchronizedMap保證其API方法的一致性。其餘的,你需要做客戶端同步