6

それはReentrantReadWriteLock一人の作家と複数の読者を対象としていると言われています。

それでも、リーダーは、バッファーにデータが存在するまで待つ必要があります。

だから、何をロックするのですか?

次のような同時実行オブジェクトを作成しました。

private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
protected final Lock readLock = rwl.readLock();
protected final Lock writeLock = rwl.writeLock();
protected final Condition hasData = writeLock.newCondition();

今書き込みメソッドで私はします:

writeLock.lock();

// writing first portion and updating variables

hasData.signalAll();

// if required then writing second portion and updating variables

hasData.signalAll();

しかし、リーダーを書く方法は?取得するだけでreadLockいいですか?しかし、それではどのようにして信号を待つことができるのでしょうか?それがまた取得する場合、writeLock読み取り/書き込みロックの優位性はどこにありますか?

必要な変数がによってのみ保護されている場合、読み取り中に必要な変数が変更されないようにするにはどうすればよいwriteLockですか?

キューはタスクに一致しません

これはについての質問ですReentrantReadWriteLock

4

4 に答える 4

7

readLockには条件がないため、ReentrantReadWriteLockは確かに少し混乱します。条件を待つためだけに、リーダーでwriteLockにアップグレードする必要があります。

作家で。

writeLock.lock(); //locks all readers and writers
// do write data
hasData.signalAll();
writeLock.unlock();

リーダーでは、次のことを行います。

readLock.lock(); //blocks writers only
try{
 if(!checkData()) //check if there's data, don't modify shared variables
 {
  readLock.unlock();
  writeLock.lock(); // need to lock the writeLock to allow to use the condition.
                    // only one reader will get the lock, other readers will wait here      
  try{
   while(!checkData()) // check if there' still no data
   {
     hasData.await(); //will unlock and re-lock after writer has signalled and unlocked.
   }
   readLock.lock();    // continue blocking writer
  }
  finally
  {
    writeLock.unlock(); //let other readers in
  }
 }
 //there should be data now
 readData(); // don't modify variables shared by readers.
}
finally
{
  readlock.unlock(); //let writers in
}

もちろん、完全を期すために、各unlock()はfinallyブロックに含める必要があります。

于 2012-10-26T15:01:08.327 に答える
3

しかし、リーダーを書く方法は?readLockのみを取得する必要がありますか?しかし、それではどのようにして信号を待つことができるのでしょうか?writeLockも取得する場合、読み取り/書き込みロックの優位性はどこにありますか?

私はBlockingQueueあなたのためにこれらすべてを処理するを使用するように切り替えます。読者はqueue.take()、キューに要素が存在するのを待っているブロックを呼び出すことができます。

あなたの作家はもう少し複雑です。私がすることは次のようなものです:

// initially try to put an element into the queue
if (!queue.offer(element)) {
   // if the queue is full then take an element off the head and just drop it
   // this won't block and may not remove anything due to race conditions
   queue.poll();
   // this put will never block because now there will be space in the queue
   queue.put(element);
}

複数のライターがいる場合、これは機能しません。synchronizedその場合はロックが必要です。固定サイズのキューを扱っている場合は、ArrayBlockingQueueがうまく機能するはずです。

于 2012-10-26T14:10:53.260 に答える
0

ブロッキング動作を持つプリミティブを使用して非ブロッキング動作を実現することはできません。ライターに「書き込みをして、誰も待たない」ようにしたい場合は、言及したロックが存在することさえ知らないようにする必要があります。

実行すると

 rwl.writeLock().lock();

リーダーが動作している場合、ライターは待機します。

「待機しない」条件を尊重したい場合は、待機なし(少なくともロックなし)のプリミティブを使用するようにしてください。たとえば、ConcurrentLinkedQueueと、リーダー間の競合状態を管理するためにのみ使用されるロックメカニズムを使用します。

于 2012-10-26T14:08:37.033 に答える
0

必要なのは、2つの別々のロックとを提供することです。LinkedBlockingQueue takeLockputLock

Offerputキューのメソッドは常に使用しますputLockが、takeメソッドは常に使用しますtakeLock

于 2012-10-26T14:19:31.577 に答える