15

私はここで尋ねられた質問を参照し、著者のコード例を使用しています、今私の質問は

  1. なぜ作成者はを使用するのですか?synchronizedMapは常に2つのスレッドが操作synchronized(synchronizedMap)を実行しようとしていないことを確認するため、本当に必要なのですか?なぜそのマップ自体で操作する必要があるのですか?read/putMapsynchronize

説明をいただければ幸いです。


  public class MyClass {
  private static Map<String, List<String>> synchronizedMap =
      Collections.synchronizedMap(new HashMap<String, List<String>>());

  public void doWork(String key) {
    List<String> values = null;
    while ((values = synchronizedMap.remove(key)) != null) {
      //do something with values
    }
  }

  public static void addToMap(String key, String value) {
    synchronized (synchronizedMap) {
      if (synchronizedMap.containsKey(key)) {
        synchronizedMap.get(key).add(value);
      }
      else {
        List<String> valuesList = new ArrayList<String>();
        valuesList.add(value);
        synchronizedMap.put(key, valuesList);
      }
    }
  }
}
4

2 に答える 2

18

なぜsynchronizemapそれ自体を同期する必要があるのですか?

コレクションに対して 2 つの操作を実行しているため、既に同期されているコレクションで同期する必要がある場合があります。例では、 acontainsKey()と aput()です。コレクションを呼び出しているコードで競合状態から保護しようとしています。さらに、この場合、ブロックは値も保護するため、複数のスレッドがこれらの非同期コレクションに値を追加できます。synchronizedArrayList

リンク先のコードを見ると、まずキーの存在を確認し、キーが存在しない場合は値をマップに入れます。2 つのスレッドがキーの存在をチェックしてから、それらの両方がマップに入れられるのを防ぐ必要があります。競争は、どちらが最初に置き、どちらが前の置きを上書きするかです。

同期されたコレクションは、マップ自体を破壊する複数のスレッドから自身を保護します。マップへの複数の呼び出しに関するロジックの競合状態からは保護されません。

synchronized (synchronizedMap) {
    // test for a key in the map
    if (synchronizedMap.containsKey(key)) {
      synchronizedMap.get(key).add(value);
    } else {
      List<String> valuesList = new ArrayList<String>();
      valuesList.add(value);
      // store a value into the map
      synchronizedMap.put(key, valuesList);
   }
}

これが、ConcurrentMapインターフェイスにputIfAbsent(K key, V value);. これには2 つの操作が必要ないため、同期する必要がない場合があります。

ところで、上記のコードを次のように書き直します。

synchronized (synchronizedMap) {
    // test for a key in the map
    List<String> valuesList = synchronizedMap.get(key);
    if (valueList == null) {
      valuesList = new ArrayList<String>();
      // store a value into the map
      synchronizedMap.put(key, valuesList);
    }
    valuesList.add(value);
}

最後に、マップ上のほとんどの操作をブロック内で行う必要がある場合は、 にsynchronizedお金を払わず、常にブロック内でsynchronizedMap使用することもできます。HashMapsynchronized

于 2012-07-26T14:43:30.203 に答える
2

これは、synchronizedMap値を更新するだけでなく、マップに影響を与える一連の操作に関するものです。同じメソッド内でマップ上で発生する2つの操作があります。

ブロック/メソッドを同期しない場合、Thread1が最初の部分を実行し、thread2が2番目の部分を実行するような場合があると想定すると、ビジネス操作によって奇妙な結果が生じる可能性があります(マップの更新が同期されている場合でも)

于 2012-07-26T14:43:47.830 に答える