CDV ❯ Allow wait() inside of a read lock
-
New Feature
-
Status: Open
-
2 Major
-
Resolution:
-
-
-
prodmgmt
-
Reporter: tgautier
-
October 05, 2007
-
0
-
Watchers: 0
-
March 19, 2010
-
Description
After a discussion w/Tim & Steve about this, there seems to be no obvious reason why we disallow wait() inside of a read lock.
Comments
Saravanan Subbiah 2009-02-16
Saravanan Subbiah 2009-02-16
Normally blockUntil* is always write locked. The reason wait/notify is implemented on only write lock is that you traditionally wait for some condition to occur (which should happen under write lock because it is changing state) and then make more changes to the state. Like waiting for a put to happen before taking from a queue.
One can argue that it will be useful to do waiting on read lock for operations like peek on a queue. But I think it is rare cases and people normally either use write locks for those cases or return null if the condition is not met ( or both like LinkedBlockingQueue.peek())
If really want to solve your particular case without incurring extra penalty for reading existing mappings you could do something like this.
public void putSomething(K k, V v) { synchronized (map) map.put(k, v); maping.notifyAll(); // You can also design to notify based on key } }
public V blockingGetSomething(K k) throws InterruptedException { V v = getSomething(k); if(v == null) { v = blockUntilMappingExistsFor(k); } return v; }
public V blockMappingExistsFor(K k) throws InterruptedException { V v; // WRITE LOCKED synchronized (map) { while ((v = map.get(k)) == null) { map.wait(); } } return v; }
public V getSomething(K k) { //READ LOCKED synchronized (map) { return map.get(k); } }
Taylor Gautier wrote:
In other words, here’s what I consider to be a perfectly good use case for a wait inside a read lock, so I ask what is the preferred method of implementation if waits inside a read lock are not honored (by Java or Terracotta, your preference!)
Map<K, V> map = new …;
public void putSomething(K k, V v) { synchronized (map) map.put(k, v); map.notifyAll(); } }
public void blockingGetSomething(K k) throws InterruptedException { V v = null;
// read lock here - either with Terracotta, or convert to RRWL synchronized (map) { while ((v = map.get(k)) == null) { map.wait(); }
return v; }
—– Original Message —– From: “Taylor Gautier” [email protected] To: “Saravanan Subbiah” [email protected] Cc: “eng” [email protected] Sent: Monday, February 16, 2009 4:20:29 PM GMT -08:00 US/Canada Pacific Subject: Re: [Eng] wait inside read lock
Yet take a look at my use case - is it idiomatic then to check a condition under a read lock, and if not true, exit the lock, re-enter a write lock and then check the condition again, and if not true, wait for the condition?
Alex Miller 2009-02-25
Summarizing some comments from the ensuing email thread about why we don’t allow this:
1) ReentrantReadWriteLocks only allow wait on the writeLock, not the readLock: “The write lock provides a Condition implementation that behaves in the same way, with respect to the write lock, as the Condition implementation provided by ReentrantLock.newCondition() does for ReentrantLock. This Condition can, of course, only be used with the write lock. The read lock does not support a Condition and readLock().newCondition() throws UnsupportedOperationException. “
2) We remove the jvm synchronization on the lock in case of reads.
3) Wait/lock typically waits for some condition (changing state) to occur. Changing that state must occur under a write lock.
Also because traditionally it doesnt make sense to wait on read lock. This is true in ReentrantReadWriteLocks lock too.
From java doc,
“Condition support
The write lock provides a Condition implementation that behaves in the same way, with respect to the write lock, as the Condition implementation provided by ReentrantLock.newCondition() does for ReentrantLock. This Condition can, of course, only be used with the write lock.
The read lock does not support a Condition and readLock().newCondition() throws UnsupportedOperationException. “
Steven Harris wrote: