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

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 块中。

于 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

您需要的是提供两个独立的锁和.LinkedBlockingQueue takeLockputLock

Offer,put队列的方法总是使用putLockwhere astake方法总是使用takeLock

于 2012-10-26T14:19:31.577 回答
0

您无法使用具有阻塞行为的原语来实现非阻塞行为。如果你真的希望作者“写而不等任何人”,他甚至不应该知道你提到的锁存在。

当你执行

 rwl.writeLock().lock();

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

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

于 2012-10-26T14:08:37.033 回答