如何使用ReentrantReadWriteLock等待数据?

时间:2012-10-26 13:59:36

标签: java concurrency java.util.concurrent reentrantreadwritelock

据说,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 个答案:

答案 0 :(得分: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应该可以正常运行。

答案 1 :(得分:2)

ReentrantReadWriteLock确实有点令人困惑,因为readLock没有条件。 您必须升级到阅读器中的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块中。

答案 2 :(得分:0)

使用具有阻塞行为的基元无法实现非阻塞行为。如果你真的希望作者“写作并且永远不会等待任何人”,他甚至不应该知道你提到的锁存在。

执行时

 rwl.writeLock().lock();

如果有读者操作,作者将会等待。

如果您想要尊重“永不等待”的条件,您应该尝试使用无等待(至少无锁)原语。例如,使用ConcurrentLinkedQueue和锁定机制,该机制仅用于管理读者之间的竞争条件。

答案 3 :(得分:0)

您需要的是LinkedBlockingQueue ,它提供两个单独的锁 takeLockputLock

队列的

Offerput方法始终使用putLock,其中take方法始终使用takeLock