14

私は次のことを行う ConcurrentHashMap を持っています:

sequences = new ConcurrentHashMap<Class<?>, AtomicLong>();

if(!sequences.containsKey(table)) {
    synchronized (sequences) {
        if(!sequences.containsKey(table))
            initializeHashMapKeyValue(table);
    }
}

私の質問は - 余分なものを作る必要はありませんか

if(!sequences.containsKey(table))

他のスレッドが同じハッシュマップ値を初期化しないように、同期ブロック内をチェックしますか?

チェックが必要なのかもしれませんが、間違っていますか?私がしていることは少しばかげているように思えますが、必要だと思います。

4

6 に答える 6

21

ConcurrentHashMap のすべての操作はスレッドセーフですが、スレッドセーフ操作は構成可能ではありません。アトミックを操作のペアにしようとしています:マップ内の何かをチェックし、そこにない場合はそこに何かを置きます(私は推測します)。したがって、質問に対する答えはyesです。もう一度確認する必要があります。コードは問題ないようです。

于 2013-02-13T10:48:26.703 に答える
17

のputIfAbsentメソッドを使用する必要がありConcurrentMapます。

ConcurrentMap<String, AtomicLong> map = new ConcurrentHashMap<String, AtomicLong> ();

public long addTo(String key, long value) {
  // The final value it became.
  long result = value;
  // Make a new one to put in the map.
  AtomicLong newValue = new AtomicLong(value);
  // Insert my new one or get me the old one.
  AtomicLong oldValue = map.putIfAbsent(key, newValue);
  // Was it already there? Note the deliberate use of '!='.
  if ( oldValue != newValue ) {
    // Update it.
    result = oldValue.addAndGet(value);
  }
  return result;
}

私たちの中の機能的純粋主義者にとって、上記は次のように単純化 (または複雑化) できます。

public long addTo(String key, long value) {
    return map.putIfAbsent(key, new AtomicLong()).addAndGet(value);
}

そして Java 8 では、不必要な の作成を避けることができますAtomicLong:

public long addTo8(String key, long value) {
    return map.computeIfAbsent(key, k -> new AtomicLong()).addAndGet(value);
}
于 2013-02-13T10:51:16.440 に答える
4

ConcurrentHashMapで排他ロックを取得することはできません。このような場合は、SynchronizedHashMapを使用することをお勧めします。

オブジェクトがまだ存在しない場合は、ConcurrentHashMap内に配置するアトミックメソッドがすでに存在します。putIfAbsent

于 2013-02-13T10:42:29.917 に答える
1

私はあなたがそこで何をしたかを見ます;-) 質問はあなた自身でそれを見ますか?

まず、「ダブル チェック ロック パターン」と呼ばれるものを使用しました。場合によっては同期を必要としない高速パス (最初に含まれる) と、複雑な操作を行うために同期が必要な低速パスがある場合。あなたの操作は、マップ内に何かがあるかどうかを確認し、そこに何かを配置/初期化することで構成されます。したがって、ConcurrentHashMap が単一の操作に対してスレッドセーフであることは問題ではありません。これは、ユニットとして扱われる必要がある 2 つの単純な操作を実行するためです。そうです、この同期ブロックは正しく、実際には、たとえば他のものによって同期される可能性がありますthis

于 2013-02-13T10:51:08.110 に答える