The usage pattern arose from following reasons:
I need read thread to wait for data if it is absent with conditions.
Read lock does not support condition, so condition should be taken from write lock.
Since read thread will wait for condition, it should aquire write lock too to wait.
I have the following locks definition in class:
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
protected final Lock readLock = rwl.readLock();
protected final Lock writeLock = rwl.writeLock();
protected final Condition hasData = writeLock.newCondition();
In my writer method I have the following pattern:
try {
writeLock.lock();
//...
if( something_written ) {
hasData.signalAll();
}
}
finally {
writeLock.unlock();
}
In my read method I have the following pattern
try {
readLock.lock();
while( data_absent ) {
// I need to acquire write lock to wait for condition!
try {
// first releasing read lock since we can't acquire write lock otherwise
// unfortunately this won't release a lock if it was acquired more than once (reentrant)
readLock.unlock();
// acquiring write lock to wait it's condition
writeLock.lock();
hasData.await(1000, TimeUnit.MILLISECONDS);
}
finally {
// releasing write lock back
writeLock.unlock();
// reacquiring read lock
// again see note about reentrancy
readLock.lock();
}
}
// reading
}
finally {
readLock.unlock();
}
Is the pattern above correct?
The problem is that if reader is reentrant, i.e. locking read more than once, then the releasing code does not work and reader hangs at the line of obtaining write lock.