Java 如何使用ReentrantReadWriteLock等待数据?

Java 如何使用ReentrantReadWriteLock等待数据?,java,concurrency,java.util.concurrent,reentrantreadwritelock,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();

据说,
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();
现在在write方法中,我执行以下操作:

writeLock.lock();

// writing first portion and updating variables

hasData.signalAll();

// if required then writing second portion and updating variables

hasData.signalAll();
但是如何写一个读者呢?它是否应该只获取
readLock
?但它怎么能等待信号呢?如果它还获得一个
写锁
,那么读/写锁的优势在哪里

如果所需变量仅受
writeLock
保护,如何确保它们在读取过程中不会更改

队列与任务不匹配


这是关于
ReentrantReadWriteLock

的问题,使用具有阻塞行为的原语无法实现非阻塞行为。如果你真的想让作者“写并且从不等待任何人”,他甚至不应该知道你提到的锁的存在

当你执行

 rwl.writeLock().lock();
如果有读卡器正在运行,编写器将等待

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

但是如何写一个读者呢?它应该只获取readLock吗?但它怎么能等待信号呢?如果它还获得写锁,那么读/写锁的优势在哪里

我会改用一个能帮你解决所有问题的电脑。您的读者可以调用
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);
}
如果有多个编写器,这将不起作用。你需要一个
同步的
锁。如果您处理的是一个固定大小的队列,那么应该可以正常工作。

您需要的是提供两个独立锁的
takeLock
putLock


Offer
put
队列的方法始终使用
putLock
其中as
take
方法始终使用
takeLock
可重入的tradewritelock确实有点混乱,因为readLock没有条件。 您必须在读卡器中升级到writeLock才能等待条件

在作者那里

writeLock.lock(); //locks all readers and writers
// do write data
hasData.signalAll();
writeLock.unlock();
在reader中,您需要:

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

您可能会发现Disruptor库很有趣,因为它很好地解决了这类问题。正如所解释的,阻塞队列确实与任务匹配。为什么在所有情况下都要写数据?你可以进行设置,使写作永远不会失败。我已经调整了我的答案@UmNyobe。最初,它没有处理这样一种情况,即她想丢弃最旧的数据以在队列中腾出空间。阻塞队列现在应该可以处理这些更改。@UmNyobe任务没有完整解释。问题在于
ReentrantReadWriteLock
而不是如何解决该任务。奇怪的是,没有寻找解决方案,但不管怎样。一个要考虑的事情是“SuzanCioc”,如果你正在做IO,你很可能浪费时间过早地优化锁,因为你的应用程序将被IO绑定,这将是不必要的。忘了它。首先,我正在以高速发送不同大小的二进制数据。其次,
queue.offer()
不会等待,也不会写入任何数据。在任何情况下我都需要写数据,所以不同大小的二进制数据就可以了。例如,它可以是
字节[]
的队列。正确的。我编辑了我的答案,以考虑到您始终希望添加到队列中的@SuzanCioc.queue不匹配。我正在使用像
InputStream
OutputStream
这样的接口,因此很难实现边界间读取(但我在以前的版本中做到了)。无论如何,任务描述非常简短,只是为了澄清主要问题。任务信息不足以改进整个解决方案。我仍然不明白为什么队列不能工作。输入流为您提供一个
字节[]
。我不明白
ReentrantReadWriteLock
如何将您从interboundary read issue@SuzanCioc中解救出来。我说的“不等待”是指不等待条件。但我当然需要一些等待来保持一致性。但是如果我也获得了
writeLock
,那么如何从单独的锁中获益呢?有一个锁不是更好吗?只有在没有数据时才获取writeLock,并且在等待条件时隐式释放它。只要有数据,多个读卡器就会同时读取。