Sunday, November 2, 2014

Different types of Locking in a threaded(multi or Uni) environment in Java

Hi friends,

I am back after a long hiatus. I became so wrapped up in several things that I forgot to share my experience here for a long time. Anyways, let's move forward with today's post.

Recently I delved into Java threading. In my experience , I did not come across a single web application that makes use of the java threading utilities(which is a shame really, since they are so versatile and useful; the other reason may be that they are bit tough to understand and implement). So , while going through different threading techniques, I stumbled upon a concept of threading called as locking. The more I read, the more confused I became. At last I was able to get myself out of such a tangled mess with some help. So here I will post about locking in a way that it's easy to understand .

What is Locking ?

Locking is a way in which a thread accesses a resource and tells other threads that they cannot access the same resource until he is done using it. So , that means when we use the synchronized keyword on a method or a code block , only one thread at a time can access it. Other threads will wait until the thread accessing it is finished with it's operation. That's called locking; means the resource is locked and no one else can access it unless it's unlocked for future use.

Types of Locking 

There are actually two types of locking:

1> Intrinsic Locking
2> Explicit Locking

Intrinsic locking are of different types like : Object level locking, class level locking and re entrant locking.

Object Level Locking :

Object level locking is using the synchronized key word on a non static method or a non static code block.So in such a type of locking, multiple threads will enter the class using different instances or objects of the class, but only one thread will have a lock on the method or the code block for a particular instance . This makes instance level data thread safe .

public class Death
{
    public synchronized void deathEaters(){} //non static method
}

or

public class Harbinger
{
    public void War(){
        synchronized (this) //non static code block
        {
            
        }
    }
}

Class Level Locking :

Class level locking comes into play when synchronized key word is used on a static method or a static code block. That means at a given instance , if there are 100 threads, then only one thread can enter the method or code block. Other threads will be waiting . This comes into play because of  the nature of a static method. A static method is always available at class level and it is shared by all instances. Hence the need to have this type of locking here .

public class Death
{
    public synchronized static void deathEaters(){} // static method
}

or

public class Harbinger
{
    public static void War(){
        synchronized (Harbinger.class) //static code block
        {
            
        }
    }
}


Re entrant locking :

This is an interesting concept. Synchronized methods are re entrant in nature .If a thread has lock on the monitor object using one synchronized method  and if another synchronized method requires to have the lock on the same monitor object then the thread can enter that method . That's why it is called re entrant ( the ability to re enter ) . Consider the following :

public class Famine{

public synchronized death(){
    plague();
  }

  public synchronized plague(){
    
  }
}

If a thread enters death(), it has the lock on Famine object, so when it tries to execute plague() method, the thread is allowed to execute plague() method since it’s already holding the lock on the Famine object.

Explicit Locking :

Explicit locking is a way of introducing thread safety  without using synchronized keyword. Instead we can use the Lock API present in java.util.concurrent package to introduce locking.

public class Resource {
public void doResourcing(){
    }
public void dologging(){
    }
}

public class ExplicitLockingUsingSynchronized implements Runnable{
    private Resource resource;
public ExplicitLockingUsingSynchronized(Resource r){
        this.resource = r;
    }
     
    @Override
    public void run() {
        synchronized (resource) {
            resource.doResourcing();
        }
        resource.dologging();
    }
}

Now let's try this using the Lock API and we will remove the synchronized keyword.

public class ExplicitLockingImplementation implements Runnable{

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

Now do you see the difference : There a lot of  API related methods to help us with locking in the Lock API(for eg, usage of time out as I have shown here). It makes our job much, much easier . We can use a lot of conditions  and options using the lock API.

That's all on thread locking. I hope this will be very informative for people who are trying to understand the concept of locking in threads .

No comments:

Post a Comment