October 5, 2022

Static Synchronization in Java

In the post Synchronization in Java it has already been discussed that every object in Java has a single lock (also called monitor) associated with it. When a thread enters a synchronized method or synchronized block it acquires that lock. All other threads attempting to execute the same code (in synchronized method or synchronized block) have to wait for the first thread to finish and release the lock.

But what about the scenario where you have more than one object of the same class. In that case two separate threads can acquire locks of these two objects and enter the synchronized method or synchronized block with those separate locks at the same time. If you don’t want that to happen then you need static synchronization in Java.

Static synchronization

As you must be knowing a variable or method marked as static in Java belongs to the type not to objects and such variable or method would be shared among the instances of the class. Same way static synchronization in Java is also at the class level not at instance level.

Static synchronization Java Example

Let’s try to clarify static synchronization in Java with an example. Here we have a class with two methods, in one of the method there is a for loop running from 1 to 5 and those values are displayed, in another method for loop runs from 5 to 1 and values are displayed.

Two objects of this class ctr1 and ctr2 are created. Four threads are also created out of which two share the ctr1 object where as the other two share the ctr2 object. What you need is that the threads are executed in such a way that the values in the loop are displayed in order i.e. 1,2,3,4,5 and 5,4,3,2,1. For that you have also synchronized the methods increment() and decrement().

// Class whose object will be shared
class Counter{
  public synchronized void increment(){		
    for(int i = 1; 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();
      }
    } 
  }
	
  public synchronized void decrement(){		
    for(int i = 5; i > 0 ; i--){
      System.out.println(Thread.currentThread().getName() + " i - " + i);		   
    } 		
  }
}

class MyIncrementRunnable implements Runnable{
  Counter ctr;
  MyIncrementRunnable(Counter ctr){
    this.ctr = ctr;
    Thread t = new Thread(this);
    t.start();
  }
  @Override
  public void run() {
    ctr.increment();
  }
}

class MyDecrementRunnable implements Runnable{
  Counter ctr;
  MyDecrementRunnable(Counter ctr){
    this.ctr = ctr;
    Thread t = new Thread(this);
    t.start();
  }
  @Override
  public void run() {
    ctr.decrement();
  }
}

public class SynchronizedDemo {
  public static void main(String[] args) throws InterruptedException {
    // Two objects shared among threads
    Counter ctr1 = new Counter();
    Counter ctr2 = new Counter();
    
    // Thread 0 and Thread 1 for increment and decrement with same object
    MyIncrementRunnable mi1 = new MyIncrementRunnable(ctr1);
    MyDecrementRunnable md1 = new MyDecrementRunnable(ctr1);
    
    // Thread 2 and Thread 3 for increment and decrement with same object
    MyIncrementRunnable mi2 = new MyIncrementRunnable(ctr2);
    MyDecrementRunnable md2 = new MyDecrementRunnable(ctr2);
  }
}
Output
Thread-0 i - 1
Thread-3 i - 5
Thread-3 i - 4
Thread-3 i - 3
Thread-3 i - 2
Thread-3 i - 1
Thread-2 i - 1
Thread-0 i - 2
Thread-2 i - 2
Thread-0 i - 3
Thread-2 i - 3
Thread-0 i - 4
Thread-2 i - 4
Thread-0 i - 5
Thread-2 i - 5
Thread-1 i - 5
Thread-1 i - 4
Thread-1 i - 3
Thread-1 i - 2
Thread-1 i - 1

As you can see from the output since thread-0 and thread-1 are synchronized on the same object ctr1 so these two thread won’t interleave. Same way thread-2 and thread-3 are synchronized on the same object ctr2 so these two threads won’t interleave. But thread-2 can enter the synchronized method even when thread-0 has acquired a lock as they both have separate object locks of their own.

Using static synchronization

To fix this problem you need to use static synchronization to have synchronization at the class level not at the instance level. With static synchronization in Java, the thread acquires the intrinsic lock for the Class object associated with the class.

In the above example you just need to make methods increment() and decrement() as static too.

// Class whose object will be shared
class Counter{
  public static synchronized void increment(){		
    for(int i = 1; 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();
      }
    } 
  }
	
  public static synchronized void decrement(){		
    for(int i = 5; i > 0 ; i--){
      System.out.println(Thread.currentThread().getName() + " i - " + i);		   
    } 		
  }
}
Output
Thread-0 i - 1
Thread-0 i - 2
Thread-0 i - 3
Thread-0 i - 4
Thread-0 i - 5
Thread-2 i - 1
Thread-2 i - 2
Thread-2 i - 3
Thread-2 i - 4
Thread-2 i - 5
Thread-3 i - 5
Thread-3 i - 4
Thread-3 i - 3
Thread-3 i - 2
Thread-3 i - 1
Thread-1 i - 5
Thread-1 i - 4
Thread-1 i - 3
Thread-1 i - 2
Thread-1 i – 1

static synchronized block in Java

You can also have static synchronized block in Java, rather than using the object reference you will have to synchronize the class object itself.

General form of static synchronized block in Java
Synchronized(CLASS_NAME.class)

Example code

In the above example you can change methods increment() and decrement() to have synchronized blocks with class reference.

// Class whose object will be shared
class Counter{
  public void increment(){
    // synchronized block with class reference
    synchronized(Counter.class){
      for(int i = 1; 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();
        }
      } 
    }
  }
	
  public void decrement(){	
    synchronized(Counter.class){
      for(int i = 5; i > 0 ; i--){
        System.out.println(Thread.currentThread().getName() + " i - " + i);		   
      } 	
    }
  }
}

That's all for the topic Static Synchronization in Java. If something is missing or you have something to share about the topic please write a comment.

You may also like

No comments:

Post a Comment