Basic Guide To java.util.concurrent.Locks Interface

Posted By : Ankur Bansala | 19-Aug-2018

(1) Overview

 The Lock interface (java.util.concurrent.lock) has been around in java 1.5. It provides us to perform extensive operations of locking.

In a simple way, a lock is a more flexible thread synchronization compare to standard synchronized block. In this blog, we’ll explore different implementations of the Lock interface with an example.

 

 

 

 

(2)  Difference between Synchronized block and Lock :  

 

You can find out a few differences between the use of synchronized block and Lock API’s:

 

  •  A synchronized block is contained in a method and lock API's method lock() and unlock() operations can be used in the separate method.
     

  • In synchronized block, You can not specify the preference to the Thread that which thread is going to acquire the lock ones released and in Lock APIs, By using fairness properties we can achieve that longest waiting Thread is access to lock.
     

  • While using synchronized block, If Thread can't get access to the synchronized block then that the Thread gets blocked but Lock API provides tryLock() method. The thread will acquire the lock only if its available and not held by another thread. So, blocking time will be reduced of thread waiting for the lock. 
     

  • If A thread is in "waiting" state and wants to acquire the access to the synchronized block, then it cannot be interrupted, but in lock API there is a method called lockInterruptibly() which can be used to interrupt the thread when it is waiting for the lock.

  •  

    (3) Lock API:

  • Let's explore the method of Lock interface:


     
  • void lock(): If the lock is available it will acquire the lock and if the lock is not available a thread gets blocked until the lock is released.
     

  • void lockInterruptibly(): Both lockInterruptibly() and lock() method is similar, lockInterruptibly() method allows the blocked thread to be interrupted and resume the execution and this method thrown java.lang.InterruptedException in addition.
     

  • Note: If an instance is locked then it should be unlocked to avoid deadlock condition. For example
     

  • boolean tryLock():  It can be used when you want to acquire the lock immediately and it will return true if locking succeeds. This method is a non-blocking version of lock() method.
     

  •  boolean tryLock(long timeout, TimeUnit timeUnit): This is overloaded method and similar to the tryLock(), it excepts given timeout before giving up trying to acquire the lock.

     

  • void unlock(): It uses to unlock the lock instances.

 

 

 

Lock lock = ...; 
lock.lock();
try {
    // access to the shared resource
} finally {
    lock.unlock();
}

 

 

(4) Lock Implementation :  

 

(4.1) ReentrantLock :

 

 

 While accessing the shared resources, The ReentrantLock class gives us the synchronization to methods and implements Lock interface.

Shared resource or code is surrounded by lock and unlocks method. It Blocks all other threads and gives a lock to the current working thread.

As the name says, ReentrantLock allows threads to enter into lock more than once on a resource.

On the time of first entering into the lock, a hold count is set to be one.

Every time hold count is incremented by one, Before unlocking the thread can re-enter into lock again.

Hold count is decremented by one, for every unlocks request,  and

the resource is unlocked when hold count is 0.

A fairness parameter also given by Reentrant Locks,  i.e. after a thread unlocks the resource, resources given to that thread

which has been waiting for the longest time.

By passing true to the constructor of the lock fairness mode is set up.

 

 

 

public class SharedObject {
    //...
    ReentrantLock lock = new ReentrantLock();
    int counter = 0;
 
    public void perform() {
        lock.lock();
        try {
            // Critical section here
            count++;
        } finally {
            lock.unlock();
        }
    }
    //...
}
Example with tryLock() :

public void performTryLock(){
    //...
    boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS);
     
    if(isLockAcquired) {
        try {
            //Critical section here
        } finally {
            lock.unlock();
        }
    }
    //...
}

 

 

In above example, the thread is calling tryLock() method and it will wait for one sec and after one sec it will give up for waiting if the lock is not available.

 

 

(4.2.) StampedLock : 

 

Stampedlock is introduced in Java 1.8. It does support read and write both locks. In StampedLock, lock acquiring methods returns a stamp and that stamp is used to release a lock and it also checks if the lock is still valid or not. see the example below :

 

 


The optimistic lock is another feature which is there in StampedLock. Sometimes, read operation does not want to wait for the write operation to complete So, there is no need of read locking instead of we can upgrade to read lock. See the example below : 

 

 

 

public String readWithOptimisticLock(String key) {
    long stamp = lock.tryOptimisticRead();
    String value = map.get(key);
 
    if(!lock.validate(stamp)) {
        stamp = lock.readLock();
        try {
            return map.get(key);
        } finally {
            lock.unlock(stamp);               
        }
    }
    return value;
}

 

 

 

 

Conclusion : 

 

 

In this blog, we have gone through the implementation of Lock interface and also gone through the newly introduced StampedLock with implementation. I hope this will help you to explore further.

 

 

 

 

 

 

 

 

 

 

About Author

Author Image
Ankur Bansala

Ankur is an experienced Java back-end Developer and having capabilities to build web application.

Request for Proposal

Name is required

Comment is required

Sending message..