4

私がマルチスレッド アプリケーションで一般的に使用するデータ構造は、すべて同じキーを共有する項目のグループを保存する ConcurrentHashMap です。この問題は、特定のキー値の最初のアイテムをインストールするときに発生します。

私が使用してきたパターンは次のとおりです。

final ConcurrentMap<KEYTYPE, Set<VALUETYPE>> hashMap = new ConcurrentHashMap<KEYTYPE, Set<VALUETYPE>>();
// ...
Set<VALUETYPE> newSet = new HashSet<VALUETYPE>();
final Set<VALUETYPE> set = hashMap.putIfAbsent(key, newSet)
if (set != null) {
  newSet = set;
}
synchronized (newSet) {
  if (!newSet.contains(value)) {
    newSet.add(value);
  }
}

この操作を行うためのより良いパターンはありますか? これもスレッドセーフですか?Setよりも内側に使用するのに適したクラスはありjava.util.HashSetますか?

4

2 に答える 2

5

これにはGoogle Guavaライブラリ、特にMultimapの実装を使用することを強くお勧めします。HashMultimapが最善の策ですが、同時更新オプションが必要な場合は、Multimaps.synchronizedSetMultimap()を使用してデリゲートでラップする必要があります。

もう 1 つのオプションは、a ComputingMap(これも Guava から) を使用することです。これは、への呼び出しから返された値がget(Key)存在しない場合、そこでインスタンス化されるマップです。はMapMakerComputingMapを使用して作成されます。

あなたの質問のコードはおおよそ次のようになります。

ConcurrentMap<KEYTYPE, Set<VALUETYPE>> hashMap = new MapMaker()
                 .makeComputingMap(
        new Function<KEYTYPE, VALUETYPE>() {
         public Graph apply(KEYTYPE key) {
           return new HashSet<VALUETYPE>();
         }
       });

は、特定のキーを呼び出すと null が返さFunctionれる場合にのみ呼び出されます。get()これは、次のことができることを意味します。

hashMap.get(key).put(value);

HashSet<VALUETYPE>が存在しない場合は作成されることを安全に認識します。

MapMakerまた、返されたマップの調整を制御できるため、メソッドを使用して同時実行レベルなどを指定できるため、関連性がありますconcurrencyLevel()。あなたはそれが役に立つと思うかもしれません:

更新操作間で許可される同時実行をガイドします。内部サイジングのヒントとして使用します。テーブルは内部的に分割され、指定された数の同時更新を競合なしで許可しようとします。これらのパーティションへのエントリの割り当ては必ずしも均一ではないため、実際に観察される同時実行性は異なる場合があります。

于 2012-03-22T12:34:32.760 に答える
0

and を使用すると、同時実行の問題を解決できるjava.util.concurrent.ConcurrentSkipListMapと思います。java.util.concurrent.ConcurrentSkipListSet

于 2012-03-22T12:35:14.110 に答える