2016-11-23 2 views
1

私のアプリケーションでは、scoreと一緒にuserIdsのリストを格納するインメモリHashMapを維持する必要があります。Writerスレッドが1つしかなく、マップの構造的変更が行われていない場合、java HashMapの取得を同期させる必要がありますか?

ビジネスロジックに基づいてユーザーのスコアを更新するWriter Threadが1つあります。多くの読者スレッドは、このマップから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.

を1として。そのようなユースケースに対しては、ConcurrentHashMapやその他のSynchronization構造を使用する必要がありますか?

+5

適切な同期がないと、「読み取り」スレッドが正しい値を読み取るという保証はありません。 – TheLostMind

+0

はい、そうです。 – DejaVuSansMono

+0

[競争条件](https://en.wikipedia.org/wiki/Race_condition)は引き続き発生しますが、あなたのケースではConcurrentModificationExceptionは発生しません。よい並行性の実践を調べるために、私はこのressourceを勧めます:http://jcip.net/ –

答えて

5

map.put操作ではvalueフィールドがHashMap$Nodeに更新されます。これはHashMapの構造的整合性に関しては安全ですが、valueフィールドにはデータ競争があります。値の種類がIntegerLong、またはDoubleのような単純な値クラスの場合、データ競争でも参照を解除することは安全ですが、消費者に更新されたスコアが表示されるという保証はありません。

この問題を解決するには、たとえば、 Longと値のタイプとしてAtomicLongがあります。マップは更新されません。その値はスレッドセーフな方法で変更されます。

これは、ソリューションの概要である:

  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(); 
    } 
    
関連する問題