Monday, February 6, 2017

Java Lock API

java.util.concurrent.locks

Most of the times, synchronized keyword is the way to go but it has some shortcomings that lead the way to inclusion of Lock API in Java Concurrency package. Java 1.5 Concurrency API came up with java.util.concurrent.locks package with Lock interface and some implementation classes to improve the Object locking mechanism.

Some important interfaces and classes in Java Lock API are:

Lock: This is the base interface for Lock API. It provides all the features of synchronized keyword with additional ways to create different Conditions for locking, providing timeout for thread to wait for lock. Some of the important methods are lock() to acquire the lock, unlock() to release the lock, tryLock() to wait for lock for a certain period of time, newCondition() to create the Condition etc.

Condition: Condition objects are similar to Object wait-notify model with additional feature to create different sets of wait. A Condition object is always created by Lock object. Some of the important methods are await() that is similar to wait() and signal(), signalAll() that is similar to notify() and notifyAll() methods.

ReadWriteLock: It contains a pair of associated locks, one for read-only operations and another one for writing. The read lock may be held simultaneously by multiple reader threads as long as there are no writer threads. The write lock is exclusive.

ReentrantLock: This is the most widely used implementation class of Lock interface. This class implements the Lock interface in similar way as synchronized keyword.On class level, ReentrantLock is a concrete implementation of Lock interface provided in Java concurrency package from Java 1.5 onwards. As per Javadoc, ReentrantLock is mutual exclusive lock, similar to implicit locking provided by synchronized keyword in Java, with extended feature like fairness, which can be used to provide lock to longest waiting thread. Lock is acquired by lock() method and held by Thread until a call tounlock() method. Fairness parameter is provided while creating instance of ReentrantLock in constructor. ReentrantLock provides same visibility and ordering guarantee, provided by implicitly locking, which means, unlock() happens before another thread get lock().


We need to understand ReentrantLock class only here to understand as it is most commonly used implementation. 

Java Lock Example – ReentrantLock in Java

Now let’s see a simple example where we will replace synchronized keyword with Java Lock API.
Let’s say we have a Resource class with some operation where we want it to be thread-safe and some methods where thread safety is not required.
public class Resource {

 public void doSomething(){
  //do some operation, DB read, write etc
 }
 
 public void doLogging(){
  //logging, no need for thread safety
 }
}
Now let’s say we have a Runnable class where we will use Resource methods.
public class SynchronizedLockExample implements Runnable{

 private Resource resource;
 
 public SynchronizedLockExample(Resource r){
  this.resource = r;
 }
 
 @Override
 public void run() {
  synchronized (resource) {
   resource.doSomething();
  }
  resource.doLogging();
 }
}
Notice that I am using synchronized block to acquire the lock on Resource object. We could have created a dummy object in the class and used that for locking purpose.

Now let’s see how we can use java Lock API and rewrite above program without using synchronized keyword. We will use ReentrantLock in java.
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConcurrencyLockExample implements Runnable{

 private Resource resource;
 private Lock lock;
 
 public ConcurrencyLockExample(Resource r){
  this.resource = r;
  this.lock = new ReentrantLock();
 }
 
 @Override
 public void run() {
  try {
   if(lock.tryLock(10, TimeUnit.SECONDS)){
   resource.doSomething();
   }
  } catch (InterruptedException e) {
   e.printStackTrace();
  }finally{
   //release lock
   lock.unlock();
  }
  resource.doLogging();
 }

}
As you can see that, I am using tryLock() method to make sure my thread waits only for definite time and if it’s not getting the lock on object, it’s just logging and exiting. Another important point to note is the use of try-finally block to make sure lock is released even if doSomething() method call throws any exception.

Java Lock vs synchronized

Based on above details and program, we can easily conclude following differences between Java Lock and synchronization.
  • Java Lock API provides more visibility and options for locking, unlike synchronized where a thread might end up waiting indefinitely for the lock, we can use tryLock() to make sure thread waits for specific time only.
  • Synchronization code is much cleaner and easy to maintain whereas with Lock we are forced to have try-finally block to make sure Lock is released even if some exception is thrown between lock() and unlock() method calls.
  • synchronization blocks or methods can cover only one method whereas we can acquire the lock in one method and release it in another method with Lock API.
  • synchronized keyword doesn’t provide fairness whereas we can set fairness to true while creating ReentrantLock object so that longest waiting thread gets the lock first.
  • We can create different conditions for Lock and different thread can await() for different conditions.
Benefits of ReentrantLock in Java

1) Ability to lock interruptibly.
2) Ability to timeout while waiting for lock.
3) Power to create fair lock.
4) API to get list of waiting thread for lock.
5) Flexibility to try for lock without blocking.

Key feature of RentrantLock

Two key feature of ReentrantLock, which provides more control on lock acquisition is trying to get a lock with ability to interrupt, and a timeout on waiting for lock, these are key for writing responsive and scalable systems in Java. In short, ReentrantLock extends functionality of synchronized keyword in Java and open path for more controlled locking in Java.


Read more: http://javarevisited.blogspot.com/2013/03/reentrantlock-example-in-java-synchronized-difference-vs-lock.html#ixzz4XuwzWiVW

No comments:

Post a Comment

Interview Prep: Java full stack

 SOLID principle :  https://www.educative.io/answers/what-are-the-solid-principles-in-java Design Pattern:  Creational:  https://medium.com...