2017-07-13 6 views
4

このセクションでは、java.util.concurrent.LinkedBlockingQueue.put()メソッドから、At​​omicIntegerは必要ないと思います。 lock()内にスレッドが1つしかないことを考慮してください。私は正しいですか?ロック内のAtomicIntegerの使用方法

putLock.lockInterruptibly(); 
    try { 
     while (count.get() == capacity) { 
      notFull.await(); 
     } 
     enqueue(node); 
     c = count.getAndIncrement(); 
     if (c + 1 < capacity) 
      notFull.signal(); 
    } finally { 
     putLock.unlock(); 
    } 

多くの質問を確認しましたが、回答が見つかりませんでした。私の質問:そこに一つだけのスレッドがロックの内側にあるので、なぜそこに2つのロックがありますが、ここで

+4

がプロデューサ/コンシューマキューに必要です。彼らは別のスレッドにあるからです。 'put'はプロデューサーのエンドポイントであり、' take'は消費者のエンドポイントです。 –

+0

ああ、私は完全にその点を逃した。あなたに同意。ありがとう –

+3

'put'と' take'が異なるロックを使用するという事実の他に、まったくロックを保持しないでアクセスすることもできます。 'size()'または 'remainingCapacity()'で指定します。また、 'peek()'と 'poll()'(タイムアウトなし)は、 'count'がゼロの時にロックを持たないショートカットを使います。 – Holger

答えて

7

LinkedBlockingQueueが互いをブロックすることなく続行する同時puttake動作を可能にするために、2つの異なるロック、putLocktakeLockを使用して、既に存在すると仮定すると、キュー内のノードが、容量が使い果たさ(またはすべてではないに制限)していません。

この場合、countには2つのスレッドが同時にアクセスできます。コンシューマスレッドとプロデューサスレッドは異なるロックを使用するため、ロック自体はプロデューサとコンシューマ間で必要なメモリの可視性の保証を確立しません。実際にはcountのアトミックアップデートです。

さらに、ロックを保持せずにcountにアクセスするsize()またはremainingCapacity()のようなノンブロッキング操作もあります。また、peek()poll()(タイムアウトなし)のようないくつかの操作では、ロックを取得する前にcountをテストするショートカットがあり、カウントがゼロのときにロックなしですぐにnullを返します。

+3

'異なるロックを使用すると、ロック自体が必要なメモリの可視性保証を確立しません - 優れています!一般にロックはメモリの可視性を確立しますが、すべてのスレッドで使用される*同じ*ロックでなければなりません – Eugene

5

をのAtomicIntegerを使用する:

private final ReentrantLock putLock = new ReentrantLock(); 

private final ReentrantLock takeLock = new ReentrantLock(); 

put方法は、実際にputLockによって保護されますが、他のスレッドはcountにアクセスしています(別のものでない限りput)それを更新することができます。正しく更新されていることを確認するには、Atomicにする必要があります。

関連する問題