ConcurrentHashMap
Javaでの使用は何ですか? その利点は何ですか?それはどのように機能しますか?サンプルコードも役に立ちます。
6 に答える
ポイントは、HashMap
スレッドセーフな実装を提供することです。古いデータや破損したデータを受信する可能性なしに、複数のスレッドが読み取りと書き込みを行うことができます。 ConcurrentHashMap
は独自の同期を提供するため、アクセスを明示的に同期する必要はありません。
のもう 1 つの機能は、指定されたキーが存在しない場合にアトミックにマッピングを追加するメソッドをConcurrentHashMap
提供することです。次のコードを検討してください。putIfAbsent
ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>();
// some stuff
if (!myMap.contains("key")) {
myMap.put("key", 3);
}
別のスレッドが への呼び出しと へ"key"
の呼び出しの間にのマッピングを追加する可能性があるため、このコードはスレッドセーフではありません。正しい実装は次のようになります。contains
put
myMap.putIfAbsent("key", 3);
ConcurrentHashMap
マップへの同時アクセスを許可します。HashTables もマップへの同期アクセスを提供しますが、マップ全体がロックされて操作を実行できなくなります。
ConcurrentHashMap の背後にあるロジックは that ですyour entire table is not getting locked
が、part[ segments
] のみです。各セグメントは独自の HashTable を管理します。ロックは更新にのみ適用されます。検索の場合、完全な同時実行が可能です。
容量が 32 のマップで 4 つのスレッドが同時に動作しているとします。テーブルは 4 つのセグメントに分割され、各セグメントが容量のハッシュ テーブルを管理します。コレクションはデフォルトで 16 個のセグメントのリストを維持し、それぞれがマップの 1 つのバケットを保護 (またはロックオン) するために使用されます。
これは事実上、16 個のスレッドが一度にコレクションを変更できることを意味します。この同時実行レベルは、オプションのconcurrencyLevel コンストラクター引数を使用して増やすことができます。
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel)
他の回答が述べたように、 ConcurrentHashMap はputIfAbsent()
、キーが存在する場合に値がオーバーライドされないことを除いて、 put に似た新しいメソッドを提供します。
private static Map<String,String> aMap =new ConcurrentHashMap<String,String>();
if(!aMap.contains("key"))
aMap.put("key","value");
上記のように回避するため、新しい方法も高速double traversing
です。contains
メソッドはセグメントを見つけ、テーブルを反復してキーを見つける必要があり、再びメソッドput
はバケットを走査してキーを配置する必要があります。
本当に大きな機能上の違いは、例外をスローしたり、使用中に他の誰かが変更したときに破損したりしないことです。
通常のコレクションでは、(反復子を介して) アクセスしているときに別のスレッドが要素を追加または削除すると、例外がスローされます。ConcurrentHashMap を使用すると、変更を加えることができ、スレッドを停止しません。
あるスレッドから別のスレッドへの変更の特定時点の可視性について、同期の保証や約束を行うものではないことに注意してください。(これは、シリアル化可能なデータベース分離のように動作する同期マップではなく、read-committed データベース分離のようなものです。(古い学校の行ロック SQL シリアル化可能であり、Oracle 風のマルチバージョン シリアライズ化ではありません:))
私が知っている最も一般的な使用法は、多くのスレッドが同じものにアクセスしている可能性がある App Server 環境で、不変の派生情報をキャッシュすることです。2 つのスレッドが同じキャッシュ値を計算して 2 回入れても、インターリーブするため、実際には問題になりません。など。
メモ化に使用できます。
import java.util.concurrent.ConcurrentHashMap;
public static Function<Integer, Integer> fib = (n) -> {
Map<Integer, Integer> cache = new ConcurrentHashMap<>();
if (n == 0 || n == 1) return n;
return cache.computeIfAbsent(n, (key) -> HelloWorld.fib.apply(n - 2) + HelloWorld.fib.apply(n - 1));
};
1.ConcurrentHashMap はスレッドセーフです。つまり、一度に 1 つのスレッドでコードにアクセスできます。
2.ConcurrentHashMap は、 Map の特定の部分を同期またはロックします。ConcurrentHashMap のパフォーマンスを最適化するために、Map は同時実行レベルに応じて異なるパーティションに分割されます。そのため、Map オブジェクト全体を同期する必要はありません。
3.デフォルトの同時実行レベルは 16 です。したがって、マップは 16 の部分に分割され、各部分は異なるロックで管理されます。これは、16 のスレッドが動作できることを意味します。
4.ConcurrentHashMap は NULL 値を許可しません。そのため、 ConcurrentHashMap でキーを null にすることはできません。