Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a ReadWriteLock render the synchronized keyword unnecessary?

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?

like image 799
Cedric Martin Avatar asked Dec 08 '11 00:12

Cedric Martin


People also ask

Why are locks better than synchronized?

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.

Is synchronized keyword reentrant?

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.

What is the advantage of the new lock interface over a synchronized block in Java?

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.


1 Answers

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).

like image 51
yshavit Avatar answered Oct 27 '22 00:10

yshavit