2017-03-28 5 views
2

volatileキーワードの背後にある原則を理解しています。 ConcurrentHashMap源に見たとき、あなたはすべてのノードとの値が値が複数のスレッドからの書き込み/読み出しをすることができますので、理にかなっている、volatile宣言されていることがわかります、揮発性とArrayBlockingQueueとおそらく他の同時オブジェクト

static class Node<K,V> implements Map.Entry<K,V> { 
    final int hash; 
    final K key; 
    volatile V val; 
    volatile Node<K,V> next; 
    ... 
} 

しかし、ArrayBlockingQueueソースに探してそれは複数のスレッドから読み取る/更新されているプレーンな配列です:

private void enqueue(E x) { 
    // assert lock.getHoldCount() == 1; 
    // assert items[putIndex] == null; 
    final Object[] items = this.items; 
    items[putIndex] = x; 
    if (++putIndex == items.length) 
     putIndex = 0; 
    count++; 
    notEmpty.signal(); 
} 

それはitems[putIndex]に挿入された値は、配列内の要素が揮発性でないことを提供し、別のスレッドから見えるようになることが保証されている方法(Iその宣言を知っている配列そのものは、要素そのものには何の効果もありません)? 他のスレッドがキャッシュされた配列のコピーを保持できませんでしたか?

おかげ

答えて

5

enqueueprivateであることに注目してください。すべてのコールを探してください(offer(E), offer(E, long, TimeUnit), put(E))。

public void put(E e) throws InterruptedException { 
    checkNotNull(e); 
    final ReentrantLock lock = this.lock; 
    lock.lockInterruptibly(); 
    try { 
     // Do stuff. 
     enqueue(e); 
    } finally { 
     lock.unlock(); 
    } 
} 

ですから、enqueueへのすべての呼び出しがlock.lock() ... lock.unlock()によって保護されてlock.lock/unlockは、メモリバリアであるため、あなたはvolatileを必要としないと結論づけることができますように、これらのルックスの一つ一つがいることに注意してください。

+0

はい私はそれに気付いたが、私はロックがメモリの障壁として役立つという手がかりはなかった。私は同期があると思ったが、ロックについてはわからなかった。本気ですか? lock()が行うのは、現在のスレッドを排他的な所有者としてマークし、内部状態を設定するためです。私はそれがどのようにメモリの障壁に関連しているのかわかりません – paranoidAndroid

+0

あなたは正しいです、javaの文書では、ロックはsynchronizedと同じメモリ意味を提供しなければならないと言います。だから私はそれが内部的にどのように動作するのだろうか。これらのロックのためのコンパイラによる特定の処理があるかもしれませんか? – paranoidAndroid

1

私の理解によれば、すべてのBlockingQueue実装は既にConcurrentHashMapとは違ってロック機構を持っているので、volatileは必要ありません。 Queueのパブリックメソッドを見ると、同時アクセスを守るReentrantLockが見つかります。

関連する問題