2016-11-23 41 views
1

在我的應用程序中,我需要維護內存HashMap,其中存儲着userIds及其score列表。我們是否需要同步java HashMap獲取是否只有一個寫入程序線程,並且沒有對地圖進行結構修改

有一個Writer線程根據業務邏輯更新用戶的得分。許多讀者主題閱讀該地圖的用戶score,即map.get(userId)

userIds的列表是靜態的,即沒有新用戶添加到地圖中。

按JavaDoc中If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.

我不會做任何結構性變化(沒有添加/刪除)。我需要使用ConcurrentHashMap還是其他Synchronization這樣的用例呢?

+5

沒有正確的同步,不能保證「讀」線程將讀取正確的值 – TheLostMind

+0

是的,你應該。 – DejaVuSansMono

+0

[Race condition](https://en.wikipedia.org/wiki/Race_condition)仍會發生,但不會發生ConcurrentModificationException。爲了研究良好的併發練習,我推薦這個資源:http://jcip.net/ –

回答

5

您的map.put操作將更新value字段HashMap$Node。這對於HashMap的結構一致性來說是安全的,但是在value字段中仍然存在數據競賽。如果您的值類型是簡單的值類,如Integer,LongDouble,即使在數據競賽中也可以對其進行取消引用,但不能保證消費者會看到更新的分數。

乾淨的解決方案是取代你的LongAtomicLong作爲值類型。那麼你的地圖將永遠不會更新,只有它的值將以線程安全的方式進行變異。

這是解決方案的概要:

  1. 安全地發佈地圖:

    volatile Map<Player, Long> scores; 
    
    void publishScores() { 
        scores = unmodifiableMap(createScoresMap()); 
    } 
    
  2. 更新得分:

    void updateScore(Player p, long score) { 
        map.get(p).set(score); 
    } 
    
  3. 閱讀總譜:

    long getScore(Player p) { 
        return map.get(p).get(); 
    } 
    
相關問題