As suggested in several answers to this question:
What is the name of this locking technique?
I implemented a ReentrantReadWriteLock and saw a great speedup (I knew there was some lock contention in one my class and using a reentrant lock did help speed things up).
But now I am wondering: if inside a class all access (both reads and writes) are done by first locking either a read-lock or a write-lock, does it mean the synchronized keyword shouldn't be used anymore in that class?
For example, here's one official Java 1.6 example found at http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
class RWDictionary {
private final Map<String, Data> m = new TreeMap<String, Data>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public Data get(String key) {
r.lock();
try { return m.get(key); }
finally { r.unlock(); }
}
public String[] allKeys() {
r.lock();
try { return m.keySet().toArray(); }
finally { r.unlock(); }
}
public Data put(String key, Data value) {
w.lock();
try { return m.put(key, value); }
finally { w.unlock(); }
}
public void clear() {
w.lock();
try { m.clear(); }
finally { w.unlock(); }
}
}
There's no synchronize keyword.
Now I realize that one of the point of such locks is to be faster than other methods (in this case faster than synchronize) but what is the technical explanation behind this?
Does the use of a read-write lock in a class in every get/update method "replace" the synchronize keyword for these methods?
Only one thread is allowed to access only one method at any given point of time using a synchronized block. This is a very expensive operation. Locks avoid this by allowing the configuration of various locks for different purpose.
synchronized block are reentrant in nature i.e if a thread has lock on the monitor object and if another synchronized block requires to have the lock on the same monitor object then thread can enter that code block.
A thread can take a lock only once. Synchronized blocks don't offer any mechanism of a waiting queue and after the exit of one thread, any thread can take the lock.
If you read the javadocs on ReadWriteLock, and of Lock, they specifically say that Locks have to provide the same memory semantics as the synchronized
keyword:
All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in The Java Language Specification, Third Edition (17.4 Memory Model):
(That's from the Lock javadoc; the ReadWriteLock refers to Lock to describe its semantics.)
So, yes, it replaces the synchronized
keyword. In fact, you could replace every synchronized
block in your code with a Lock and have the same semantics (and, depending on jvm, possibly even a small performance boost.) But you'd be trading a bit of speed for a lot more verbosity, and if you ever forget to unlock one of those locks, you could deadlock your program.
What powers a lot of this is nonblocking algorithms (compare-and-swap being the heart of them) combined with the memory semantics of volatile
fields, which specify that if you write to a volatile
field, any thread that subsequently reads that field has to see at least the same state of the world as you saw when you wrote it. (They could also see some or all of what happened after that write.) Those tools can make for some pretty fast code, but they're also subtle and easy to get wrong -- it's almost always best to stay with the higher-level constructs (such as the ReadWriteLock you're using).
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