Pros and Cons of Lock (java.util.concurrent.locks) over synchronized methods and statements

An explicit lock(Lock) and implicit lock(synchronize method & statement) is a tool for controlling access to a shared resource by multiple threads.Every object in Java has implicit monitor lock and synchronize(method & statements/blocks) take advantage of that and JVM provide automatic lock management, however explicit locking is achieved using Lock/ReadWriteLock introduced in Java 1.5, with intention to give programmer more flexibility and control over Lock. The main agenda of this post is to discuss pros and cons of explicit locking over synchronize methods/statements .

Pro and Cons of explicit locking(Lock/ReentrantLock) over implicit locking(synchronize methods and statements):- 

1. High flexibility and programmatic control  -
Pros:- In synchronize method and statement, JVM does automatic management of lock(release of lock) and developer does not have any control over it. Lock interface gives programmatic control and flexibility over Lock by providing API for non-blocking attempt to acquire a lock(tryLock(), tryLock(long, TimeUnit)), getting hold on lock (lokcRef.lock()), release lock(lockRef.release()), etc.
Cons:- Lock is not easy to use as synchronized methods and statements(JVM does automatic release of lock and optimization too- just acquire implicit lock and forget).However,when dealing with explicit lock , it is developer responsibility to acquire lock and release appropriately.
Note:- Brian Goetz, author of  "Java Concurrency in Practice" states that, if you forget to wrap the unlock() call in finally block,your code will probably appear to run properly, but you've created a time bomb that may well hurt innocent bystanders. So, handle explicit lock with caution.

2. Chain locking supported -
Pros:- synchronize method and statement allows multiple locking, does not allow chain locking.In other words,all locks released by JVM in the same lexical scope in which they were acquired and  in opposite order.Refer following diagram for better understanding, locks acquired in critical section 3 must be released in that scope and returns to critical section 2.
Implicit monitor lock acquire and release cycle for multiple locks
However, Lock supports chain locking, it is not mandatory to release lock in the same lexical scope in which they were acquired, thus allows multiple locks to be acquired and released in any order.So, lock acquired in critical section 2 can be released in critical section 3 and critical section 3 lock can be released in somewhere else.
Cons:- The scoping mechanism for synchronized methods and statements makes it much easier to program with monitor locks and helps avoid many common programming errors involving locks. However, with Lock programmer responsibility increases("with great power comes great responsibility, here version has changed, with this increased flexibility comes additional responsibility). When locking and unlocking occur in different scopes, all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.
Lock lockObj = new ReentrantLock();// or others classes 
lockObj.lock();
 try {
  // access the resource protected by this lock
 } finally {
  lockObj.unlock();
 }

3. Performance improvement:- ReentrantLock (a concrete implementation of Lock interface) offered better performance than intrinsic locking in Java 1.5 and in Java 1.6 this performance gap was minimized.Refer following diagram showing advantage of explicit locking over Intrinsic Locking - ReentrantLock Performance on Java 5.0 and Java6.
Note:- Even tough performance of explicit locking is better than implicit locking, but performance should not be criteria to select it over implicit locking.
Intrinsic Locking Versus ReentrantLock Performance on Java 5 and Java 6 (Diagram reference :Java Concurrency in Practice by Brian Goetz)

4. Fairness locking support:-
ReentrantLock constructor provides flexibility to create two types of lock: a fair lock and unfair lock(default ).Threads acquire a fair lock in the order in which they requested it, whereas a non-fair lock permits forceful lock acquisition. By default implicit locking provide unfair locking(using semaphore fair locking can be created).
Note:- 
  • When non-fair lock is created, any thread can jump the queue and acquire lock on the given object, if that moment lock is free and available to be acquired.
  • With a fair lock, a newly requesting thread is queued if the lock is held by another thread or if threads are queued waiting for the lock. However, with a non-fair lock, the thread is queued only if the lock is currently held.
  • Performance of non-fair lock is better than fair lock. In fair lock, pause of one thread and start another thread causes a substantial overhead and with increase threads count performance degraded.Refer following diagram, which shows throughput of fair and non-fair lock. 
Fair Versus Non-fair Lock Performance (Diagram reference  :Java Concurrency in Practice by Brian Goetz)

What we should choose - Implicit lock and explicit lock ?

Implicit lock is very easy to use and JVM does lock management for it. However, ReentrantLock has an edge over implicit lock in terms of performance gain.
It is recommended to prefer implicit locking(synchronized methods and statements) over explicit locking unless we need to use explicit locking advanced features: timed, polled, or interruptible lock acquisition, fair queuing, or non block structured locking.
Note:-
  • If we are using Java 5, the threading problems (like deadlocked threads) cannot be debugged using ReentrantLock because JVM does not have any information about which threads hold ReentrantLocks(this issue was addressed in Java 1.6). However,with implicit lock using thread dumps can detect and identify deadlocked threads because thread dumps shows mapping between call frames and locks.
  • With performance improvement synchronized is going to get more benefit over ReentrantLock because synchronized is built into JVM and JVM manages it lock internally. So, it is not a good idea to choose ReentrantLock over synchronized for performance reasons.

2 Comments

Previous Post Next Post