2015-12-21 79 views
1

我有我從多個線程填充一個ConcurrentHashMap的地圖,如下圖所示:填充從多個線程

private static Map<ErrorData, Long> holder = new ConcurrentHashMap<ErrorData, Long>(); 

public static void addError(ErrorData error) { 
    if (holder.keySet().contains(error)) { 
     holder.put(error, holder.get(error) + 1); 
    } else { 
     holder.put(error, 1L); 
    } 
} 

有競爭狀態在上面的代碼中的任何可能性,它可以跳過更新?如果可以提供更好的性能,我該如何在這裏使用Guava AtomicLongMap

我對Java 7中

回答

7

是的,有一個比賽,因爲你的可能性不檢查是否包含並自動放置。

可以使用AtomicLongMap如下,其執行此檢查原子:

private static final AtomicLongMap<ErrorData> holder = AtomicLongMap.create(); 

public static void addError(ErrorData error) { 
    holder.getAndIncrement(error); 
} 

正如在Javadoc描述:

[T]他典型機構,用於寫該地圖是addAndGet( K,long),它爲當前與K關聯的值添加一個long。如果鍵尚未與某個值關聯,則其隱式值爲零。

所有操作都是原子,除非另有說明。

+0

如果你看到我的例子,我在地圖上也有一個Long值,我爲每個唯一鍵遞增。最後,我打印出這張地圖,並打印出像這樣的'{SomeKey = 3}' – user1950349

+0

@ user1950349,是嗎?這就說得通了;你仍然可以使用AtomicLongMap。 –

+0

@LouisWasserman感謝您的編輯。 –

4

如果您使用的是Java 8中,您可以利用新的merge方法的優點:

holder.merge(error, 1L, Long::sum); 
+0

我仍然在Java 7.忘了提及..讓我更新我的問題。 – user1950349

4

A'香草的Java 5+的解決方案:

public static void addError(final ErrorData errorData) { 
    Long previous = holder.putIfAbsent(errorData, 1L); 
    // if the error data is already mapped to some value 
    if (previous != null) { 
     // try to replace the existing value till no update takes place in the meantime 
     while (!map.replace(errorData, previous, previous + 1)) { 
      previous = map.get(errorData); 
     } 
    } 
} 
2

在Java 7或以上版本中,你需要使用一個比較和更新循環:

Long prevValue; 
boolean done; 
do { 
    prevValue = holder.get(error); 
    if (prevValue == null) { 
    done = holder.putIfAbsent(error, 1L); 
    } else { 
    done = holder.replace(error, prevValue, newValue); 
    } 
} while (!done); 

有了這個代碼,如果兩個線程競爭一個可能最終會重試它的更新,但他們最終會得到正確的值。

考慮:

Thread1: holder.get(error) returns 1 
Thread2: holder.get(error) returns 1 
Thread1: holder.put(error, 1+1); 
Thread2: holder.put(error, 1+1); 

要解決這個問題,你需要使用原子操作來更新地圖。

+0

這與我的回答不一樣嗎? – Bax

+0

@Bax是的,但我沒有注意到它已經發布了..我剛剛看到它。 – ferhan