Jun 10, 2014

Understanding Java locks, multi-threading, and synchronized keyword. Are Java locks re-entrant? What is the difference between intrinsic and explicit locks?

7 Things you must know about Java locks and synchronized key word

  1. Each Java class and object (i.e. instance of a class) has an intrinsic lock or monitor. Don't confuse this with explicit lock utility classes that were added in Java 1.5, and I will discuss this later.
  2. If a method is declared as synchronized, then it will acquire either the instance intrinsic lock or the static intrinsic lock when it is invoked. The two types of lock have similar behavior, but are completely independent of each other.
  3. Acquiring the instance lock only blocks other threads from invoking a synchronized instance method. It does not block other threads from invoking an un-synchronized method, nor does it block them from invoking a static synchronized method.
  4. Any thread entering a synchronized  method or a block of code needs to acquire that object's or class's lock before entering to execute that method or block of code.
  5. Acquired lock is released when leaving a synchronized method or a block of code for other waiting or blocked threads to acquire.
  6. When an object has 1 or more synchronized methods or blocks of code, only one thread can acquire the lock for that object, all other threads will be blocked, and will be waiting to acquire the lock once released.
  7. When an object has 1 or more methods that are not synchronized, one or more threads can execute those methods or blocks of code simultaneously or concurrently. Threads are Not blocked, and waiting is not required.

Q. What does reentrancy mean regarding intrinsic or explcit locks?
A. Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

public synchronized void method1(){
  //intrinsic lock is acquired
  operation1(); //ok to enter this synchronized method 
                //as locks are on per thread basis
  operation2(); //ok to enter this synchronized method 
                //as locks are on per thread basis 
  //intrinsic lock is released  

public synchronized void operation1(){
    //process 1

public synchronized void operation2(){
    //process 1

In Java, both intrinsic and explicit locks are re-entrant.

Q. If 2 different threads hit 2 different synchronized methods in an object at the same time will they both continue?
A. No. Only one thread can acquire the lock in a synchronized method of an object. Each object has a synchronization lock. No 2 synchronized methods within an object can run at the same time. One synchronized method should wait for the other synchronized method to release the lock.   This is demonstrated here with method level lock. Same concept is applicable for block level locks as well.

Q. Why synchronization is important?
A. Without synchronization, it is possible for one thread to modify a shared object while another thread is in the process of using or updating that object’s value. This often causes dirty data and leads to significant errors.

Q. What is the disadvantage  of synchronization?
A. The disadvantage of synchronization is that it can cause deadlocks when two threads are waiting on each other to do something. Also, synchronized code has the overhead of acquiring lock, and preventing concurrent access, which can adversely affect performance.

Q. When every object has an intrinsic lock in Java, why were explicit lock utility classes introduced in Java 5?
A. An intrinsic locking mechanism is a clean approach in terms of writing code, and is pretty good for most of the use-cases. But, intrinsic locking mechanism do have some limitations in certain scenarios:

  • It is not possible to have more control, for example, read concurrently when not writing.
  • Intrinsic locks must be released in the same block in which they are acquired.
  • It is not possible to interrupt a thread waiting to acquire a lock.
  • It is not possible to attempt to acquire a lock without waiting for it forever.

Q. How are explicit locks laid out in Java?
A. Laid out with 2 interfaces Lock and ReadWriteLock.

java.util.concurrent.locks.Lock – simplest case of a lock which can be acquired and released.

void lock();            //acquires the lock
void lockInterruptibly() throws InterruptedException; //acquires the lock unless current thread
                                                      //is interrupted
boolean tryLock();                                    //Acquires the lock only if it is free 
                                                      //at the time of invocation.
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //Acquires the lock if it
                                                                       //is free within the given 
                                                                       // waiting time 
                                                                       //and the current thread 
                                                                       //has not been interrupted

The implementation class of the above Lock interface is java.util.concurrent.locks.ReentrantLock, which has the same basic behavior and semantics as the intrinsic lock each Java object has.

java.util.concurrent.locks.ReadWriteLock – a lock implementation that has both read and write lock types – multiple read locks can be held at a time unless the exclusive write lock is held.

//returns the lock used for reading
Lock readLock();
//returns the lock used for writing.
Lock writeLock();

Q. What are the disadvantages of explicit locks?
A. It is more complicated to use it properly, and incorrect usage can lead to unexpected issues leading to deadlocks, thread starvation, etc. So, you need to remember the following best practices when using explicit locks.

  • Release the explicit locks in a finally block. 
  • Favor intrinsic locks where possible to avoid bugs and to keep your code cleaner and easier to maintain.
  • Use tryLock( ) if you don’t want a thread waiting indefinitely to acquire a lock. This is similar to how databases prevent dead locks with wait lock timeouts.
  • When using ReentrantLocks for frequent concurrent reads and occasional writes, be mindful of the possibility that a writer could wait a very long time sometimes forever) if there are constantly read locks held by other threads.

More beginner to advanced level multi-threading questions and answers 



Post a Comment

Subscribe to Post Comments [Atom]

<< Home