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 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
- Using synchronized static method
- 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.
What will be the below code. In ClassLevelLock lock method synchronized on ObjectLevelLock.Class. What is this scenario.
ReplyDeletepackage 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();
}
}