2012-05-07 44 views
14

的Java Docs說,putIfAbsent相當於的ConcurrentHashMap把VS的putIfAbsent

if (!map.containsKey(key)) 
     return map.put(key, value); 
    else 
     return map.get(key); 

因此,如果關鍵在地圖中存在,它不會更新它的價值。它是否正確?

如果我想根據某些標準更新密鑰值,該怎麼辦?說到期時間等

這將是一個更好的impl添加和更新緩存?

public void AddToCache(T key, V value) 
{ 
    V local = _cache.putifabsent(key, value); 

    if(local.equals(value) && local.IsExpired() == false){ 
    return; 
    } 
    // this is for updating the cache with a new value 
    _cache.put(key, value); 
} 
+0

@Gray第二行。代碼說,如果密鑰不在緩存中,則放置它,否則只返回值。如果鍵值對已經在緩存中,它不會更新值。 – DarthVader

+0

雖然你的邏輯有點困難。如果'local'等於'value',那麼你只是更新了地圖。你不是說如果它不等於「價值」?這意味着地圖上已經有東西了嗎? –

+0

哦,我明白了,對不起。您正在使用「更新」一詞來表示無法創建。你是對的,對不起。 – Gray

回答

9

因此它不更新密鑰的值。它是否正確?

這是正確的。它將返回已經在Map中的當前值。

這對於添加和更新緩存會更好嗎?

一些事情會讓你的實現更好。

你不應該使用的putIfAbsent來測試它是否存在,如果你想確保,如果不存在,則putIfAbsent一個你應該只使用它。相反,您應該使用map.get來測試它的存在(或map.contains)。

V local = _cache.get(key); 
    if (local.equals(value) && !local.IsExpired()) { 
     return; 
    } 

2.相反,你會想取代放的,這是因爲可能會出現的競爭條件,其中if可以爲假由兩個或多個線程進行評估,其中一個兩個(或更多)線程將覆蓋其他線程的放入。

你可以做的反而是replace

當一切都說過和做過它可能看起來像在這當量

public void AddToCache(T key, V value) { 
    for (;;) { 

     V local = _cache.get(key); 
     if(local == null){ 
      local = _cache.putIfAbsent(key, value); 
      if(local == null) 
       return; 
     } 
     if (local.equals(value) && !local.IsExpired()) { 
      return; 
     } 

     if (_cache.replace(key, local, value)) 
      return; 
    } 
} 
+0

如果replace()返回true,則應該返回。 – jtahlborn

+0

@jtahlborn感謝剛剛注意到我自己:) –

+0

也,你不需要再次調用get()如果putIfAbsent()返回非null,你可以使用你剛剛得到的。如果替換失敗,您只需要第二次get()調用。 – jtahlborn

4

如果密鑰之前未在地圖中,您的代碼將拋出NPE。

除此之外,雖然這是一個合理的想法,但它不會在「併發」環境中工作。添加putIfAbsent()方法的原因是,映射可以使用它正在使用的任何基礎支持來管理操作的原子性,以使操作線程安全。在你的實現中,2個不同的調用者可能會彼此相繼結束(第一個用一個新的用戶代替過期的值,第二個用第二個新的用戶立即替換掉第一個)。

+0

關於併發情況的事實不能經常指出。 :) +1 – pimpf0r