Collections.synchronizedMap()
にロックしConcurrentHashMap
との差である:
複数のスレッドが頻繁Collections.synchronizedMap()
にアクセスする場合、各メソッドが共有ロックを使用して同期しているので、すなわち場合(競合の多くが存在するであろうスレッドXがCollections.synchronizedMap()
上のメソッドを呼び出すと、他のすべてのスレッドは、スレッドXが呼び出されたメソッドから戻るまでCollections.synchronizedMap()
上のメソッドを呼び出すことがブロックされます。
ConcurrentHashMap
には、可変数のロック(デフォルトは16)があり、それぞれがConcurrentHashMap
のキーのセグメントを保護します。 160鍵のConcurrentHashMap
の場合、各ロックは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();
}
わかりました。しかし、2つ以上のスレッドがサブ配列{0,63}内のすべてを変更しようとしている場合はどうでしょうか? – GedankenNebel
次に、最初に最初に処理されます。ロックを取得する最初のスレッドは変更を行い、終了すると2番目のスレッドは変更を行います。 'ConcurrentHashMap'は' replace'のようなメソッドを持っていて、第2のスレッドが誤って第1のスレッドの変更を上書きしないようにします。 –
私は理解しているように(実際にはJava Concurrencyから実際に引用したわけではありませんが)理解できるように、実際には「先着順」とは思えません。公平性は、コンストラクタ'ReentrantLock'や' ArrayBlockingQueue'のようなキューのような明示的な 'Lock'実装のために、 (私はそれが古いスレッドだと知っています、ごめんなさい) – Marcelo