2012-03-22 6 views
4

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

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

答えて

5

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

get(Key)への呼び出しから返された値が存在しない場合は、ComputingMap(Guavaからも)を使用することもできます。 ComputingMapは、MapMakerを使用して作成されます。

あなたの質問からのコードは、おおよそ次のようになります。特定のキーのためのget()への呼び出しは、そうでない場合はnullを返しだろうというとき

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

Functionのみ呼び出されます。それはまだ存在しない場合

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

が安全HashSet<VALUETYPE>が作成されていることを知っている:これは、あなたがこれを行うことができます。

MapMakerは、返されたMapのチューニングを制御するため、たとえばconcurrencyLevel()メソッドを使用して並行性レベルを指定できるため、関連性があります。それは役に立つかもしれません:

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

+0

グアバコレクションはどのようなスレッドセーフな保証をしていますか? 'HashMultimap'のためのJavaDocsから:"このクラスは、同時動作がマルチマップを更新するときにスレッドセーフではありません。 common.collect.SetMultimap)」を参照してください。 'Collections.synchronizedMap()'の性能が非常に悪いため、java.util。*コレクション内で 'concurrent'パッケージが追加されました。 – Ralph

+0

これはおそらくあなた自身を評価する必要があるでしょう。もう1つの選択肢はコンピューティングマップを使用することです - 私は答えもその例で更新します。 – Rich

+0

Guavaは完全に並行した 'Multimap'を提供していません。なぜなら、それは非常に難しいからです。 –

関連する問題