27

Java Concurrency in Practice によると、11.4.3 章には次のように書かれています。

ロック分割は、可変サイズの独立したオブジェクトのセットに対するパーティション ロックに拡張できる場合があります。この場合、ロック ストライピングと呼ばれます。たとえば、ConcurrentHashMap の実装は 16 個のロックの配列を使用し、それぞれがハッシュ バケットの 1/16 を保護します。バケット N は、ロック N mod 16 によって保護されています。

ロックのストライピングとバケットのメカニズムを理解して視覚化するには、まだ問題があります。誰かがこれをよく理解できる言葉で説明できますか:)

前もって感謝します。

4

3 に答える 3

16

Collections.synchronizedMap()aと aのロックの違いConcurrentHashMapは次のとおりです。

複数のスレッドが に頻繁にアクセスする場合Collections.synchronizedMap()、共有ロックを使用して各メソッドが同期されるため、多くの競合が発生します (つまり、スレッド X が でメソッドを呼び出すと、他のすべてのスレッドは、スレッド X までCollections.synchronizedMap()、 a でメソッドを呼び出すことがブロックされます)。Collections.synchronizedMap()呼び出したメソッドから戻ります)。

ConcurrentHashMapは可変数のロック (デフォルトは 16) があり、それぞれが 内のキーのセグメントを保護しますConcurrentHashMap。したがって、ConcurrentHashMap160 個のキーを持つ の場合、各ロックは 10 個の要素を保護します。したがって、キーを操作するメソッド ( getputsetなど) は、キーが同じセグメントにあるキーを操作する他のメソッドへのアクセスのみをロックアウトします。たとえば、スレッド 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();
}
于 2013-04-22T16:22:58.387 に答える