Thursday, July 8, 2021

Static Synchronization in Java Multi-Threading

With instance method synchronization, threads are executed one thread per instance. That may create problems when we have more than one instance of the same class. In that scenario you may have to synchronize at the class level if you want to have a single lock for all the instances of the class rather than synchronizing at object level. That is what static synchronization in Java does.

There are two ways you can have static synchronization in Java.
  • static synchronized method
  • An enclosed synchronized code block with in a static method.

Synchronized static method in Java

Synchronized instance method is synchronized on the instance(object) of the class. If a class has two objects, then two threads can acquire lock on these two objects and enter the synchronized method or block at the same time.

Synchronized static method Java example

Here we have a class Message whose object will be shared among threads. In class Message there is a method displayMsg. You want one thread to finish printing the message with in the method then only another thread should start executing the method. Here two objects of Message1 class, msg1 and msg2 are created. Then four threads are created out of which two threads share the msg1 object where as the other two share the msg2 object.

First let's see with the help of an example what problem we may face in case we don't use static synchronization.

Code without static synchronization

//This class' shared object will be accessed by threads
class Message1{
  public synchronized void displayMsg(){
    System.out.println("In run method " + Thread.currentThread().getName()); 
    for(int i = 0; i < 5 ; i++){
      System.out.println(Thread.currentThread().getName() + " i - " + i);
      try {
        Thread.sleep(50);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    } 
  }
}

class MyClass1 implements Runnable{
  Thread t; 
  Message1 msg; 
  MyClass1(Message1 msg){
    this.msg = msg; 
    t = new Thread(this);
    t.start();
  }
  @Override
  public void run() {
    msg.displayMsg();
  }
}

public class SynchronizedDemo1 {
  public static void main(String[] args) { 
    Message1 msg1 = new Message1();
    Message1 msg2 = new Message1();
    // Two threads on msg1 object
    MyClass1 mc1 = new MyClass1(msg1);
    MyClass1 mc2 = new MyClass1(msg1);
    // Two threads on msg2 object
    MyClass1 mc3 = new MyClass1(msg2);
    MyClass1 mc4 = new MyClass1(msg2);
  }
}

Output

In run method Thread-1
Thread-1 i - 0
In run method Thread-3
Thread-3 i - 0
Thread-3 i - 1
Thread-1 i - 1
Thread-3 i - 2
Thread-1 i - 2
Thread-1 i - 3
Thread-3 i - 3
Thread-3 i - 4
Thread-1 i - 4
In run method Thread-2
Thread-2 i - 0
In run method Thread-0
Thread-0 i - 0
Thread-0 i - 1
Thread-2 i - 1
Thread-0 i - 2
Thread-2 i - 2
Thread-2 i - 3
Thread-0 i - 3
Thread-0 i - 4
Thread-2 i - 4

Here it can be seen that thread-0 and thread-1 are invoked on msg1 object where as thread-2 and thread-3 are invoked on msg-2 object.

As we already know if you are using synchronization on the instance methods then the thread will have exclusive lock one per instance. In the given example two of the threads share one object and another two share another object thus thread-0 and thread-1 will be synchronized using one monitor and thread-2 and thread-3 are synchronized using another monitor.

We can see in the output thread-0 and thread-1 are not having any thread interference same way thread 2 and thread-3 are not having any thread interference but thread-1 and thread-3 are entering the synchronized method at the same time with their own respective locks. Lock hold by thread-1 will stop thread-0 from entering the synchronized method as they are working on the same instance. But it cannot stop thread-2 or thread-3 as they are working on another instance.

Code with static synchronized method

In these kinds of scenarios if we still want that a synchronized method or block is accessed by a single thread then we have to use static synchronized method or block to have synchronization at the class level rather than on the instance level.

As we know that every class loaded by the JVM is essentially an object of type Class. So, in that case too, monitor of the object is acquired but that is the monitor of the Class object that represents the class to which the static method belongs.

We just need to change the displayMsg() method to make it a static method-

//This class' shared object will be accessed by threads
class Message1{
  public static synchronized void displayMsg(){
    System.out.println("In run method " + Thread.currentThread().getName()); 
    for(int i = 0; i < 5 ; i++){
      System.out.println(Thread.currentThread().getName() + " i - " + i);
      try {
         Thread.sleep(50);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
    } 
  }
}

Output

In run method Thread-0
Thread-0 i - 0
Thread-0 i - 1
Thread-0 i - 2
Thread-0 i - 3
Thread-0 i - 4
In run method Thread-2
Thread-2 i - 0
Thread-2 i - 1
Thread-2 i - 2
Thread-2 i - 3
Thread-2 i - 4
In run method Thread-3
Thread-3 i - 0
Thread-3 i - 1
Thread-3 i - 2
Thread-3 i - 3
Thread-3 i - 4
In run method Thread-1
Thread-1 i - 0
Thread-1 i - 1
Thread-1 i - 2
Thread-1 i - 3
Thread-1 i - 4

It can be seen now how threads are executing one after another with any one thread holding the lock while it is executing.

static synchronized block in Java

Same way we can have static synchronized block where we need to synchronize the class object itself.

Java static synchronized block syntax

Synchronized(CLASS_NAME.class)

static synchronized block Java example

If we take the previous example itself and make it a static synchronized block instead of static synchronized method then Message1 class will look like

//This class' shared object will be accessed by threads
class Message1{
  public static void displayMsg(){
    System.out.println("In run method " + Thread.currentThread().getName());
    synchronized(Message1.class){
      for(int i = 0; i < 5 ; i++){
        System.out.println(Thread.currentThread().getName() + " i - " + i);
        try {
          Thread.sleep(50);
        } catch (InterruptedException e) {
           e.printStackTrace();
        }
      }
    }
  }
}

Output

In run method Thread-0
In run method Thread-3
Thread-0 i - 0
In run method Thread-1
In run method Thread-2
Thread-0 i - 1
Thread-0 i - 2
Thread-0 i - 3
Thread-0 i - 4
Thread-2 i - 0
Thread-2 i - 1
Thread-2 i - 2
Thread-2 i - 3
Thread-2 i - 4
Thread-1 i - 0
Thread-1 i - 1
Thread-1 i - 2
Thread-1 i - 3
Thread-1 i - 4
Thread-3 i - 0
Thread-3 i - 1
Thread-3 i - 2
Thread-3 i - 3
Thread-3 i - 4

See how the first statement is printed for all the threads as that statement is outside the synchronized block. But only thread-0 acquires the lock and starts its execution, all the other threads are suspended till the execution of thread-0 finishes.

That's all for this topic Static Synchronization in Java Multi-Threading. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Synchronization in Java - Synchronized Method And Block
  2. Why wait(), notify() And notifyAll() Must be Called Inside a Synchronized Method or Block
  3. Difference Between ReentrantLock and Synchronized in Java
  4. Deadlock in Java Multi-Threading
  5. Java ThreadLocal Class With Examples

You may also like-

  1. Java Multithreading Interview Questions And Answers
  2. Difference Between Encapsulation And Abstraction in Java
  3. Java Pass by Value or Pass by Reference
  4. Method Reference in Java
  5. Interface Default Methods in Java 8
  6. How HashMap Works Internally in Java
  7. Count Number of Words in a String Java Program
  8. Lazy Initialization in Spring Using lazy-init And @Lazy Annotation

2 comments:

  1. that was a great explanation thank you so much for the examples

    ReplyDelete
  2. Thanks so much for this explanation. helped me with my assignments.

    ReplyDelete