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
其中astake
方法始终使用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,并且在等待条件时隐式释放它。只要有数据,多个读卡器就会同时读取。