2013-04-22 4 views
13

でどのように動作するかを簡単に説明する必要があります。は、実践でのJava並行処理によると、章11.4.3氏は述べています「ロックストライピング」はConcurrentHashMapの

ロック分割は時々独立したオブジェクトのvariablesizedセットに ロックを分割するように拡張することができ その場合は ロックストライピングと呼ばれます。たとえば、 の実装では、ConcurrentHashMapは16個のロックの配列を使用し、各配列はハッシュバケットの1/16 を保護します。バケットNはロックN mod16で保護されています。

ロックストライピングとバケット機構を理解して視覚化するにはまだ問題があります。 誰かがこれを理解しやすい言葉で説明できますか?

ありがとうございます。

答えて

30

ハッシュマップは配列上に構築され、ハッシュ関数はオブジェクトを基本配列の要素にマップします。基になる配列に1024要素があるとしましょう。ConcurrentHashMapは実際にこれを64要素の16の異なるサブ配列に変換します。 {0、63}、{64,127}などです。各サブアレイは独自のロックを持っているため、{0、63}サブアレイを変更しても{64,127}のサブアレイ他のスレッドが第2のサブアレイに書き込む間に第1のサブアレイに書き込むことができる。次のように

+0

わかりました。しかし、2つ以上のスレッドがサブ配列{0,63}内のすべてを変更しようとしている場合はどうでしょうか? – GedankenNebel

+3

次に、最初に最初に処理されます。ロックを取得する最初のスレッドは変更を行い、終了すると2番目のスレッドは変更を行います。 'ConcurrentHashMap'は' replace'のようなメソッドを持っていて、第2のスレッドが誤って第1のスレッドの変更を上書きしないようにします。 –

+0

私は理解しているように(実際にはJava Concurrencyから実際に引用したわけではありませんが)理解できるように、実際には「先着順」とは思えません。公平性は、コンストラクタ'ReentrantLock'や' ArrayBlockingQueue'のようなキューのような明示的な 'Lock'実装のために、 (私はそれが古いスレッドだと知っています、ごめんなさい) – Marcelo

11

Collections.synchronizedMap()にロックしConcurrentHashMapとの差である:

複数のスレッドが頻繁Collections.synchronizedMap()にアクセスする場合、各メソッドが共有ロックを使用して同期しているので、すなわち場合(競合の多くが存在するであろうスレッドXがCollections.synchronizedMap()上のメソッドを呼び出すと、他のすべてのスレッドは、スレッドXが呼び出されたメソッドから戻るまでCollections.synchronizedMap()上のメソッドを呼び出すことがブロックされます。

ConcurrentHashMapには、可変数のロック(デフォルトは16)があり、それぞれがConcurrentHashMapのキーのセグメントを保護します。 160鍵のConcurrentHashMapの場合、各ロックは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(); 
} 
+0

javaのHashMapはスレッドセーフではなく、HashTableはスレッドセーフです。あなたが話す最初のシナリオはHashTableです –

2

ここで重要な概念は「バケット」です。このハッシュテーブル全体に対してグローバルロックを使用する代わりに、各バケットに1つの小さなロックを使用します。 ソートの複雑さを改善できるバケットソートにも似ています。