FULL PRODUCT VERSION :
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
ReentrantReadWriteLock blocks obtaining a read lock after trying to obtain a write lock and timing out.
So if one thread has a read lock, then a second thread does writeLock().tryLock(...), the tryLock will fail & return false. If that second thread then
does readLock().lock() it will block. This should not happen, it should be able to obtain the read lock because there are no write locks held.
A ReentrantReadWriteLock with "FAIR" policy does not show this behaviour
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Create a ReentrantReadWriteLock (rwlock)
- Thread 1 calls
rwlock.readLock().lock()
- Thread 2 calls
rwlock.writeLock().tryLock(...) // fails
rwlock.readLock().lock(). // blocks
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Thread 2 obtains read lock and continues
ACTUAL -
Thread 2 is blocked trying to get read lock
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
// Code to reproduce
import java.util.concurrent.locks.*;
import java.util.concurrent.*;
/**
* Test ReentrantReadWrite Lock.
* This code shows how we cannot regain a read lock if a write lock times out.
*/
public class TestTryWriteInRead extends Thread {
public void run() {
log("Try For Write");
try {
boolean gotWrite = lock.writeLock().tryLock(20,TimeUnit.MILLISECONDS);
if( gotWrite ) {
log("SURPRISE - got write... releasing it");
lock.writeLock().unlock();
} else {
log("Write timed out");
}
}catch(InterruptedException e) {
log("Interrupted");
}
log("Obtain Read");
lock.readLock().lock();
log("Release Read");
lock.readLock().unlock();
log("EXIT Try");
}
void log(String s) {
System.out.println(getName() + ": " + s);
}
public TestTryWriteInRead (String name, ReadWriteLock lock) {
super(name);
this.lock = lock;
}
ReadWriteLock lock;
long count;
static long stoptime;
public static void main(String[] args) {
// run this for approximately 10 seconds
stoptime = System.currentTimeMillis() + 10000;
ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock(false);
// obtain read lock
rwlock.readLock().lock();
// start 1 threads
for (int i = 1; i <= 1; i++) {
new Thread(new TestTryWriteInRead ("TryWrite"+ i, rwlock)).start();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Setting fair mode makes it work correctly.