2017-10-24 4 views
2

並行環境ではConcurrentHashMapを使用してください。しかし、通常のHashMapでJavaは何を約束したのですか? map.get("a")で値を取得しようとすると、2つのスレッドがHashMapで同じキーを変更/アクセスしようとするとどうなりますか?

Map map = new HashMap(); 

// thread 1 
map.put("a", 1) 

// thread 2 
map.put("a", 2) 

、私はマップが壊れていないし、戻り値は1または2でなければならないことを約束されるのですか?

+3

号は、それをしません。 –

+2

['HashMap'](https://docs.oracle.com/javase/9​​/docs/api/java/util/HashMap)のようにスレッドセーフでないと宣言されたコードを悪用すると、html)、行動の約束はなく、結果は予測できません。 'HashMap'ドキュメントの明快さと、あなたが[' ConcurrentHashMap'](https://docs.oracle.com/javase/9​​/docs/api/java/util/concurrent/ConcurrentHashMap.html)を知っていることを考えると、あなたの質問は意味をなさない。 –

+1

グリズリークマを華麗なドレスパーティーに招待しているのと同じです...あなたは何が起こるかを知る方法がなく、それはおそらく美しくないでしょう。 –

答えて

2

私が理解していれば、同時のシナリオでは何が起こるのか、そしてHashMapが適切かどうか(適切でないと広く知られているもの)ではないかという疑問があります。

このような非常に望ましくないシナリオでは、どのような種類の問題が発生するかを知る最も良い方法は、the source codeを分析することです。例えば、OpenJDKの1.6実装では:、この方法および属性に不在O同期機構において

public V More ...put(K key, V value) { 
    if (key == null) 
     return putForNullKey(value); 
    int hash = hash(key.hashCode()); 
    int i = indexFor(hash, table.length); 
    for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
     Object k; 
     if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
      V oldValue = e.value; 
      e.value = value; 
      e.recordAccess(this); 
      return oldValue; 
     } 
    } 

    modCount++; 
    addEntry(hash, key, value, i); 
    return null; 
} 

以下の問題の1つ以上が発生することができる:

1)非決定リターン

ライン:スレッド1用

return oldValue; 

結果が古い値とすることができる(糸1及び2つのコールの前に)、2またはnullであることができます。スレッド2のaddEntry(ハッシュ、キー、値、i)が完全に転送されているかどうかに依存します。もちろん、スレッド2と同じ問題です。

2)未定インデックスと重複キー

int i = indexFor(hash, table.length); 

table.length上依存します。したがって、このハッシュの以前の値が存在するかどうかに応じて、別のスレッドのaddEntry(hash、key、value、i)の実行に応じて、両方の呼び出しでiインデックスが異なる可能性があります。

3)壊れたサイズと一貫性

put( "a"、...)を連続して呼び出しても、マップのサイズは変更されません(少なくともキー "a" )。しかし、2つのスレッドのrace conditionsに応じて、マップサイズの一貫性が損なわれる可能性があります。すなわち、keysetのサイズはマップサイズのサイズと異なります。 modCountが将来のputとgetの呼び出しを壊してしまう可能性があるため、キーをハッシュするために使用される他の変数。

質問のコメントでどのように適切に言われましたか。予想外の動作と内部構造の損傷により、同時シナリオでのマップの使用が完全に無効になりました。

3

ハッシュマップはスレッドセーフではありません。何が起こるかは保証されていません。 スレッドの実行順序によって異なります。

+1

ここでの最後の文章は、行動がOPによって提案された選択肢のどちらか一方であることを暗示しているようですが、これは正しくありません。 – EJP

3

読み取りモードではないHashMapへのマルチスレッドアクセスは、未定義の動作を引き起こす可能性があります。

使用マップが破損するおそれが同期建設Collections.synchronizedMap(new HashMap())

関連する問題