Collections.synchronizedMap()
aと aのロックの違いConcurrentHashMap
は次のとおりです。
複数のスレッドが に頻繁にアクセスする場合Collections.synchronizedMap()
、共有ロックを使用して各メソッドが同期されるため、多くの競合が発生します (つまり、スレッド X が でメソッドを呼び出すと、他のすべてのスレッドは、スレッド X までCollections.synchronizedMap()
、 a でメソッドを呼び出すことがブロックされます)。Collections.synchronizedMap()
呼び出したメソッドから戻ります)。
にConcurrentHashMap
は可変数のロック (デフォルトは 16) があり、それぞれが 内のキーのセグメントを保護しますConcurrentHashMap
。したがって、ConcurrentHashMap
160 個のキーを持つ の場合、各ロックは 10 個の要素を保護します。したがって、キーを操作するメソッド ( get
、put
、set
など) は、キーが同じセグメントにあるキーを操作する他のメソッドへのアクセスのみをロックアウトします。たとえば、スレッド X が を呼び出しput(0, someObject)
、次にスレッド Y がそれらの呼び出しを呼び出す場合put(10, someOtherObject)
、それらの呼び出しは同時に実行でき、スレッド Y はスレッド X が から戻るのを待つ必要はありませんput(0, someObject)
。以下に例を示します。
size()
さらに、やなどの特定のメソッドisEmpty()
はまったく保護されません。これにより同時実行性が向上しますが、強力な一貫性がないことを意味します (同時に変化する状態を反映しません)。
public static void main(String[] args) {
ConcurrentHashMap<Integer, Object> map = new ConcurrentHashMap<>(160);
new Thread(new Runnable() {
@Override
public void run() {
map.put(0, "guarded by one lock");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
map.put(10, "guarded by another lock");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
// could print 0, 1, or 2
System.out.println(map.count());
}
}.start();
}