Class level Locking in Java - Walking Techie

Blog about Java programming, Design Pattern, and Data Structure.

Sunday, August 21, 2016

Class level Locking in Java

In the previous post, We have learnt about synchronization on the object. If you have not, We strongly recommend to see how to acquire object's monitor lock before moving on to this post.

In this post we will learn how to acquire class level lock.

problem in object's lock

Problem without class level lock.

Suppose we have created two objects of shared class named object1 and object2. We have two threads of each objects say t1 ,t2 and t3, t4. you can see in above diagram. In case of synchronized method or synchronized block there can't be interference between t1 and t2 or t3 and t4 because t1 and t2 threads of same object that acquire object's lock, but there can be interference between t1 and t3 or t1 and t4 because t1 and t2 acquire one object's lock and t3 and t4 acquire other object's lock. How we can solve this problem? We can solve this problem by using synchronization at class level.

Thread can acquire lock at class level by

  1. Using synchronized static method
  2. Using synchronized block

Using synchronized static method

Let's say, we have MyRunnable class. We want to use static synchronization method of this class, as soon as thread entered synchronized method, thread acquire lock at class level, rest of the threads wait to get class monitor lock. Thread will leave lock when it exits from synchronized method. static synchronized method looks like below snippet code...

public static synchronized void display() {
  //some logic here
  }

Lets, understand above explanation with a program.

public class MyRunnable implements Runnable {

 @Override
 public void run() {
  display();
 }

 public static synchronized void display() {
  System.out.println(Thread.currentThread().getName()
    + " is acquired class lock in display() method.");
  for (int i = 1; i <= 2; i++) {
   System.out.println(Thread.currentThread().getName()
     + " is executing. Value of i=" + i);
   try {
    Thread.sleep(2000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println(Thread.currentThread().getName()
    + " is completed in display() method.");
 }
}
public class ThreadDemo {

 public static void main(String[] args) {
  MyRunnable myRunnable1 = new MyRunnable();
  MyRunnable myRunnable2 = new MyRunnable();
  Thread t1 = new Thread(myRunnable1);
  Thread t2 = new Thread(myRunnable1);
  Thread t3 = new Thread(myRunnable2);
  Thread t4 = new Thread(myRunnable2);
  t1.start();
  t2.start();
  t3.start();
  t4.start();

 }
}

Output of the above program

Thread-0 is acquired class lock in display() method.
Thread-0 is executing. Value of i=1
Thread-0 is executing. Value of i=2
Thread-0 is completed in display() method.
Thread-3 is acquired class lock in display() method.
Thread-3 is executing. Value of i=1
Thread-3 is executing. Value of i=2
Thread-3 is completed in display() method.
Thread-2 is acquired class lock in display() method.
Thread-2 is executing. Value of i=1
Thread-2 is executing. Value of i=2
Thread-2 is completed in display() method.
Thread-1 is acquired class lock in display() method.
Thread-1 is executing. Value of i=1
Thread-1 is executing. Value of i=2
Thread-1 is completed in display() method.

If you notice above output, Thread-0 entered static synchronized method and was holding lock on MyRunnable's class. So, rest of the threads waited for Thread-0 to release lock on MyRunnable's class so that it could enter static synchronized method.

Using synchronized block

Let's say, we have MyRunnable class. We want to create synchronization block, and pass class name.class as parameter tells which class has to synchronized at class level. synchronized block looks like below snippet code...

synchronized (MyRunnable.class) {
//thread has acquired lock on MyRunnable class
}

As soon as thread entered synchronized block, thread acquire lock at class, rest of the threads wait to get class monitor lock. Thread will leave lock when it exits from synchronized block.

public class MyRunnable implements Runnable {

 @Override
 public void run() {
  synchronized (MyRunnable.class) {
   System.out.println(Thread.currentThread().getName()
     + " is acquired class lock in display() method.");
   for (int i = 1; i <= 2; i++) {
    System.out.println(Thread.currentThread().getName()
      + " is executing. Value of i=" + i);
    try {
     Thread.sleep(2000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   System.out.println(Thread.currentThread().getName()
     + " is completed in display() method.");
  }
 }
}
public class ThreadDemo {

 public static void main(String[] args) {
  MyRunnable myRunnable1 = new MyRunnable();
  MyRunnable myRunnable2 = new MyRunnable();
  Thread t1 = new Thread(myRunnable1);
  Thread t2 = new Thread(myRunnable1);
  Thread t3 = new Thread(myRunnable2);
  Thread t4 = new Thread(myRunnable2);
  t1.start();
  t2.start();
  t3.start();
  t4.start();
 }
}

Output of the above program

Thread-0 is acquired class lock in display() method.
Thread-0 is executing. Value of i=1
Thread-0 is executing. Value of i=2
Thread-0 is completed in display() method.
Thread-3 is acquired class lock in display() method.
Thread-3 is executing. Value of i=1
Thread-3 is executing. Value of i=2
Thread-3 is completed in display() method.
Thread-2 is acquired class lock in display() method.
Thread-2 is executing. Value of i=1
Thread-2 is executing. Value of i=2
Thread-2 is completed in display() method.
Thread-1 is acquired class lock in display() method.
Thread-1 is executing. Value of i=1
Thread-1 is executing. Value of i=2
Thread-1 is completed in display() method.

If you notice above output, Thread-0 entered synchronized block and was holding lock on MyRunnable's class. So, rest of the threads waited for Thread-0 to release lock on MyRunnable's class, so that it could enter synchronized block.

1 comment :

  1. What will be the below code. In ClassLevelLock lock method synchronized on ObjectLevelLock.Class. What is this scenario.

    package com.lock;

    // Java program to illustrate class level lock
    public class ClassLevelLock implements Runnable {

    public void run() {
    try {
    Lock();
    }
    catch ( InterruptedException l_ex ) {
    // TODO Auto-generated catch block
    l_ex.printStackTrace();
    }
    }

    public void Lock() throws InterruptedException {
    System.out.println( "Lock() : before sync block Thread:" + Thread.currentThread().getName() );
    synchronized ( ObjectLevelLock.class ) {
    System.out.println( "Lock(): in block " + Thread.currentThread().getName() );
    Thread.sleep( 2000 );
    System.out.println( "Lock() : in block " + Thread.currentThread().getName() + " end" );
    }
    }

    }
    ------------------------------------------------------------------------------------------------------------
    package com.lock;

    // Java program to illustrate
    // Object lock concept
    public class ObjectLevelLock implements Runnable {

    public void run() {
    Lock();
    }

    public void Lock() {
    System.out.println( Thread.currentThread().getName() );
    synchronized ( this ) {
    System.out.println( "in block " + Thread.currentThread().getName() );
    System.out.println( "in block " + Thread.currentThread().getName() + " end" );
    }
    }
    }
    -----------------------------------------------------------------------------------------------------------------------------------------
    package com.lock;

    public class Main {

    public static void main( final String[] args ) {
    new Main().callClassLevelLock();
    }
    public void callClassLevelLock() {
    ClassLevelLock g1 = new ClassLevelLock();
    Thread t1 = new Thread( g1 );
    Thread t2 = new Thread( g1 );
    ClassLevelLock g2 = new ClassLevelLock();
    Thread t3 = new Thread( g2 );
    Thread t4 = new Thread( g2 );
    Thread t5 = new Thread( g2 );
    t1.setName( "t1" );
    t2.setName( "t2" );
    t3.setName( "t3" );
    t4.setName( "t4" );
    t5.setName( "t5" );
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();

    }

    }

    ReplyDelete