From the ReentrantReadWriteLock class javadoc:
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
5: rwl.readLock().unlock();
6: rwl.writeLock().lock();
// Recheck state because another thread might have acquired
// write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
14: rwl.readLock().lock();
15: rwl.writeLock().unlock(); // Unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
Why must we release the read lock before acquiring the write lock as written in the comment? If the current thread holds the read lock, then it should be allowed to acquire the write lock when other threads are not reading anymore, regardless of whether the current thread also holds the read lock. This is the behavior I would expect.
I would expect the lock upgrade at lines 5 and 6 and the lock downgrade at lines 14 and 15 to be done internally in the ReentrantReadWriteLock class. Why is that not possible?
In other words, I would expect the code to work fine like this:
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// The readlock is upgraded to writeLock when other threads
// release their readlocks.
rwl.writeLock().lock();
// no need to recheck: other threads can't have acquired
// the write lock since this thread still holds also the readLock!!!
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.writeLock().unlock(); // Unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
This looks like a much better and safer way to handle locking, doesn't it?
Can somebody explain the reason for this weird implementation? Thanks.
The problem with upgrading a read lock to a write lock is, if two threads try to do it at the same time, it can lead to deadlock. Consider the following sequence:
Now there is a deadlock. Neither thread A or B can proceed, and neither will ever release the read lock.
The Javadoc explicitly states upgrading a read lock to a write lock is not possible. The reason for that is because it can create a deadlock.
Both threads are now waiting on each other ... forever.
Reentrancy allows downgrading from the write lock to a read lock, by acquiring the write lock, then the read lock and then releasing the write lock. However, upgrading from a read lock to the write lock is not possible (which results in a deadlock).
Source: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With