据说,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
的问题。
答案 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
,它提供两个单独的锁 takeLock
和putLock
。
Offer
,put
方法始终使用putLock
,其中take
方法始终使用takeLock