Friday, 26 June 2015

Synchronization in Java multithreading

In a multithreaded environment when more than one threads are trying to access a shared resource we need to have some mechanism to ensure that the resource will be used only by 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). At any given time Only one thread can own the monitor.

Before any thread executes the code which is with in a synchronized method (or synchronized block) compiler provides instructions to acquire the lock on the specified object.

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.

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 adding 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 code without synchronizing the method and later we have the same code where method is synchronized.

Here we have a class Message whose object will be shared among threads. In class Message there is a method displayMsg and you want one thread to finish printing the message with in the method then only another thread starts executing the method.

Code when synchronized is not used

// 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 is all jumbled, because all the 4 threads share the same object and synchronized keyword is not used to ensure that only single thread has the lock on the object and only that thread can execute the method.

Code when synchronized is used

If we use synchronized 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) comprises of 7 lines only then it makes sense to synchronize those 7 lines only rather than 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 of the synchronized block only then another thread enters the synchronized block.

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.

Synchronized instance method is synchronized on the instance(object) of the class. Let's assume 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.

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

Here we use the same functionality as used above of displaying a message. 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.

//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 objectthus 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();
      }
    } 
  }
}

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.

static synchronized block

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 -

2 comments: