Friday, 26 June 2015

Synchronization in Java multithreading

In a multithreaded environment when more than one thread are trying to access a shared resource we need to have some way to ensure that the resource will be used by only one thread at a time. The process by which it is ensured is called synchronization.

For achieving synchronization in Java concept of monitor is used. Every object created in Java has one associated monitor (mutually exclusive lock). Only one thread can own a monitor at any given time. When a code is within a synchronized method (or synchronized block) compiler provides instructions to acquire the lock on the specified object before any thread executes the code which is with in a synchronized method (or synchronized block).
When any thread acquires a lock it is said to have entered the monitor. All other threads which need to execute the same shared piece of code (locked monitor) will be suspended until the thread which initially acquired the lock releases it.

In case of static members to have proper synchronization we need to have a synchronized static method. 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'll go into instance method and static method synchronization in detail very soon.

Where can we use synchronized keyword

The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statements (also known as synchronized blocks). This can be further divided into use with instance methods and static methods. So, essentially we can have four different ways synchronized keyword can be used.

  • instance method
  • An enclosed code block with in an instance method (Synchronized block).
  • static method
  • An enclosed code block with in a static method.

Let's see where and why we should use a specific type of synchronized method or block.

Synchronized Instance Method

We can synchronize a method by appending synchronized keyword within a method signature.

General Form of synchronized instance method

Public synchronized void method_name(parameter_list){
}

Let's see an example code where first we write the same code with synchronizing a method and later synchronize the method.

// This class' shared object will be accessed by threads
class Message{
 public void displayMsg(String msg){
   System.out.println("Inside displayMsg method " + Thread.currentThread().getName());
   System.out.println("**" + msg); 
   try {
      Thread.sleep(10);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
   System.out.println("*");
 }
}
 
class MyClass implements Runnable{
  Thread t;
  Message msg;
  String message;
  MyClass(Message msg, String str){ 
    this.msg = msg;
    this.message = str;
    // creating threads, 4 threads will be created 
    // all sharing the same object msg
    t = new Thread(this);
    t.start();
  }
  @Override
  public void run() {
     msg.displayMsg(message);
  }
}

public class SynchronizedDemo {
  public static void main(String[] args) {
    Message msg = new Message();
    MyClass mc1 = new MyClass(msg, "I");
    MyClass mc2 = new MyClass(msg, "am");
    MyClass mc3 = new MyClass(msg, "not");
    MyClass mc4 = new MyClass(msg, "synchronized");
  }
}

Output

I got the following output, for you output may differ as it depends upon which thread is picked first.

Inside displayMsg method Thread-0
Inside displayMsg method Thread-3
**synchronized
Inside displayMsg method Thread-1
**am
Inside displayMsg method Thread-2
**not
**I
*
*
*
*

It can be seen how output has all jumbled, because all the 4 threads share the same object and a delay has been simulated using sleep. That's why the last asterisks are all coming together because sleep() method is used just before that.

If we use synchronize keyword with the method only a single thread will access the method at the given time. In that case the displayMsg() method will look like -

class Message{
    public synchronized void displayMsg(String msg){
        System.out.println("Inside displayMsg method " + Thread.currentThread().getName());
        System.out.print("**" + msg);        
        try {
            Thread.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("*");
    }
}

Output

Inside displayMsg method Thread-0
**I*
Inside displayMsg method Thread-1
**am*
Inside displayMsg method Thread-2
**not*
Inside displayMsg method Thread-3
**synchronized*

Now it can be seen how one thread finishes its execution then only another thread starts its execution of the method. Though which thread is picked first is up to the scheduler that's why the message may not print correctly but the point here is that whichever thread enters the synchronized method that finishes then only the next thread starts its execution.

Please note that a synchronized instance method is synchronized on the instance(object) of the class. So, if a class has more than one object then one thread at a time can enter each object's synchronized method.

Synchronized statement(block) in instance method

It is not always needed to synchronize the whole method, let's say we have a 100 line code method, out of which critical section (shared resource) is only 7 lines then it makes sense to synchronize only those 7 lines rather than synchronizing the whole method. That way we can improve performance.
synchronized statements must specify the object that provides the intrinsic lock.

General Form of synchronized Synchronized statement (block)

Synchronized(object_reference){
// code block
}

Though it is also possible to synchronize on a string but it is considered a bad idea as "Literal strings within different classes in different packages likewise represent references to the same String object." See this for reference - http://www.javalobby.org/java/forums/t96352.html

If we use the same example used with instance method it can be changed to use synchronized block like this -

//This class' shared object will be accessed by threads
class Message{
    public void displayMsg(String msg){
        System.out.println("Inside displayMsg method " + Thread.currentThread().getName());
        synchronized(this){
            System.out.print("**" + msg);        
            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("*");
        }
    }
}

Output

Inside displayMsg method Thread-0
Inside displayMsg method Thread-3
Inside displayMsg method Thread-2
Inside displayMsg method Thread-1
**I*
**am*
**not*
**synchronized*

It can be seen from the output how the first print statement is executed by all the threads as that is not inside the synchronized block. After that only a single thread executes at a time and finishes its execution only then another thread enters.

Synchronized static method

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.

Let's see with the help of an example what problem we may face in case we don't use 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 that if you are using synchronization on the instance methods then the thread will have exclusive lock one per instance. In the given example 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.

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

Code with static synchronized method

We just need to change the displayMsg() method to look like -
//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();
      }
    } 
  }
}

Ouput

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.

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

General form

Synchronized(CLASS_NAME.class)

In that case 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 Synchronization in Java multithreading. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Why wait(), notify() and notifyAll() must be called inside a synchronized method or block?
  2. Inter-thread communication using wait, notify and notifyAll
  3. Deadlock in Java multi-threading
  4. ThreadLocal class in Java
  5. Difference between ReentrantLock and Synchronized
  6. Java Multi-threading interview questions

You may also like -

1 comment: