JavaでのConcurrentHashMap
の使用法は何ですか?その利点は何ですか?どのように機能しますか?サンプルコードも役立ちます。
ポイントは、スレッドセーフなHashMap
の実装を提供することです。古くなったデータや破損したデータを受け取ることなく、複数のスレッドが読み書きできます。 ConcurrentHashMap
は独自の同期を提供するため、明示的にアクセスを同期する必要はありません。
ConcurrentHashMap
のもう1つの機能は、putIfAbsent
メソッドを提供することです。このメソッドは、指定されたキーが存在しない場合に原子的にマッピングを追加します。次のコードを検討してください。
ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>();
// some stuff
if (!myMap.contains("key")) {
myMap.put("key", 3);
}
別のスレッドがcontains
の呼び出しとput
の呼び出しの間に"key"
のマッピングを追加する可能性があるため、このコードはスレッドセーフではありません。正しい実装は次のとおりです。
myMap.putIfAbsent("key", 3);
ConcurrentHashMap
は、マップへの同時アクセスを許可します。 HashTablesもマップへの同期アクセスを提供しますが、マップ全体がロックされて操作が実行されます。
ConcurrentHashMapの背後にあるロジックは_your entire table is not getting locked
_ですが、部分[segments
]のみです。各セグメントは、独自のHashTableを管理します。ロックは更新にのみ適用されます。取得の場合、完全な同時実行が可能です。
容量が32のマップで4つのスレッドが同時に動作しているとしましょう。テーブルは4つのセグメントに分割され、各セグメントが容量のハッシュテーブルを管理します。コレクションは、デフォルトで16個のセグメントのリストを保持します。各セグメントは、マップの単一のバケットを保護(またはロック)するために使用されます。
これは事実上、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により、変更を行うことができ、スレッドを停止しません。
あるスレッドから別のスレッドへの変更の特定の時点の可視性について、いかなる種類の同期保証も約束もしません。 (これは、シリアライズ可能なデータベース分離のように動作する同期マップではなく、読み取りコミットされたデータベース分離のようなものです(旧式の行ロックSQLシリアライズ可能、Oracleのようなマルチバージョンシリアライズ可能:))
私が知っている最も一般的な用途は、多くのスレッドが同じものにアクセスする可能性のあるApp Server環境で不変の派生情報をキャッシュすることです。など(たとえば、Spring WebMVCフレームワーク内でURLからハンドラメソッドへのマッピングのような実行時派生の構成を保持するために広く使用されています。)
メモ化に使用できます。
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は同時実行レベルに応じて異なるパーティションに分割されます。そのため、マップオブジェクト全体を同期する必要はありません。
3.デフォルトの同時実行レベルは16です。したがって、マップは16の部分に分割され、各部分は16のスレッドが動作できることを意味する異なるロックで管理されます。
4.ConcurrentHashMapはNULL値を許可しません。そのため、ConcurrentHashMapではキーをnullにすることはできません。
こんにちは皆さん、ConcurrentHashMapについて議論しました。
ConcurrentHashMapとは何ですか?
ConcurrentHashMapは、ConcurrentMapおよびSerializableインターフェースを実装するJava 1.5で導入されたクラスです。ConcurrentHashMapは、複数のTheadingを処理するときにHashMapを拡張します。パフォーマンスの問題が発生したため、HashMapは適切な選択ではありません。
ConcurrentHashMapにはいくつかの重要なポイントがあります。
ここにConcurrentHashMapの構成があります。
ConcurrentHashMap m = new ConcurrentHashMap();:デフォルトの初期容量(16)、負荷係数(0.75)、concurrencyLevel(16)で新しい空のマップを作成します。
ConcurrentHashMap m = new ConcurrentHashMap(int initialCapacity);:指定された初期容量で、デフォルトの負荷係数(0.75)およびconcurrencyLevel(16)で新しい空のマップを作成します。
ConcurrentHashMap m = new ConcurrentHashMap(int initialCapacity、float loadFactor);:指定された初期容量と負荷係数、およびデフォルトのconcurrencyLevel(16)で新しい空のマップを作成します。
ConcurrentHashMap m = new ConcurrentHashMap(int initialCapacity、float loadFactor、int concurrencyLevel);:指定された初期容量、負荷係数、同時実行レベルで新しい空のマップを作成します。
ConcurrentHashMap m = new ConcurrentHashMap(Map m);:指定されたマップと同じマッピングで新しいマップを作成します。
ConcurretHashMapにはputIfAbsent();という名前のメソッドが1つあります。このメソッドは重複キーを保存できません。以下の例を参照してください。
import Java.util.concurrent.*;
class ConcurrentHashMapDemo {
public static void main(String[] args)
{
ConcurrentHashMap m = new ConcurrentHashMap();
m.put(1, "Hello");
m.put(2, "Vala");
m.put(3, "Sarakar");
// Here we cant add Hello because 1 key
// is already present in ConcurrentHashMap object
m.putIfAbsent(1, "Hello");
// We can remove entry because 2 key
// is associated with For value
m.remove(2, "Vala");
// Now we can add Vala
m.putIfAbsent(4, "Vala");
System.out.println(m);
}
}