1. ホーム
  2. java

ConcurrentMap の putIfAbsent を使う前に、map に key が含まれているかどうか確認する必要がある。

2023-10-03 05:48:09

質問

複数のスレッドから使用できるマップのために、JavaのConcurrentMapを使用しています。putIfAbsentは素晴らしいメソッドで、標準のマップ操作を使用するよりもはるかに簡単に読み書きができます。私は以下のようなコードを持っています。

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

// ...

map.putIfAbsent(name, new HashSet<X>());
map.get(name).add(Y);

読みやすさは抜群ですが、すでにマップにある場合でも毎回新しいHashSetを作成する必要があります。私はこう書くことができました。

if (!map.containsKey(name)) {
    map.putIfAbsent(name, new HashSet<X>());
}
map.get(name).add(Y);

この変更により、可読性は少し落ちますが、毎回HashSetを作成する必要はありません。この場合、どちらが良いのでしょうか?私は、より可読性が高いので、最初の方を支持する傾向があります。しかし、2つ目の方法の方が、パフォーマンスが良く、より正しいかもしれません。もしかしたら、これらのどちらかよりも良い方法があるかもしれません。

この方法でputIfAbsentを使用するためのベストプラクティスは何ですか?

どのように解決するのですか?

並行処理は難しいです。もし、素直なロックの代わりに並行マップをわざわざ使うのであれば、それに越したことはないでしょう。実際、必要以上にルックアップを行わないようにしましょう。

Set<X> set = map.get(name);
if (set == null) {
    final Set<X> value = new HashSet<X>();
    set = map.putIfAbsent(name, value);
    if (set == null) {
        set = value;
    }
}

(通常のstackoverflowの免責事項: 私の頭の上にオフ。テストしていません。コンパイルされていません。等々)

更新しました。 1.8で追加された computeIfAbsent にデフォルトメソッド ConcurrentMap (そして Map というのは興味深いことで、この実装は ConcurrentMap ). (そして1.7では"diamond operator"が追加されました。 <> .)

Set<X> set = map.computeIfAbsent(name, n -> new HashSet<>());

(注意:このメソッドで行われるすべての操作のスレッドセーフはあなたの責任で行ってください。 HashSet に含まれる ConcurrentMap .)