Monday, May 30, 2016

Java Threading - Usage of synchronized key word

Go through the following simple code snippet. It increment the value of variable using two threads.

public class App {
 private int number = 0;
 
 public static void main(String args[]){
   App app = new App();
   app.increment();
 } 
 public void increment(){
  Thread t1 = new Thread(new Runnable(){
   @Override
   public void run() {
    for(int i=0;i<10000;i++){
     number=number+1;
    }
   }   
  });  
  Thread t2 = new Thread(new Runnable(){
   @Override
   public void run() {
    for(int i=0;i<10000;i++){
     number=number+1;
    }
   }   
  });  
  t1.start();
  t2.start();
  
  try {
   t1.join();
  
   t2.join();
  } catch (InterruptedException e) {
   e.printStackTrace();
  }  
  System.out.println("Count is: "+ number);
 }
}

In method increment() it starts two threads, wait for them to stop and finally print the variable number.After increment 10000 times by each thread value of variable number should be 20000, because there are two threads involved in this process.

This code seems like work fine. But there is a problem. If you run it few times, you will see some times the value of variable number is lower than 20000.

Why is that..?? What is happening there..?? 

There are situations in a multi-threading environment that two or more threads access or do operations on same variable at the same time.

Figure 1 : Two threads accessing same variable at  the same time 
Figure 1 shows a simple scenario, what happens when two threads access same variable at same time.

In the above scenario,
  1. Both threads reads the same value
  2. Both threads increment retrieved value by one
  3. Both threads write the value to variable
So the expected work from two threads have not been done.

This can be prevented if we can stop two threads accessing same variable at the same time. That when synchronized keyword of the java comes to help. with that above code can be modified as follows.

public class App {
 private int number = 0;
 
 public static void main(String args[]){
   App app = new App();
   app.increment();
 }  
 public synchronized void incByOne(){
  number=number+1;
 }
 public void increment(){
  Thread t1 = new Thread(new Runnable(){
   @Override
   public void run() {
    for(int i=0;i<10000;i++){
     incByOne();
    }
   }   
  });  
  Thread t2 = new Thread(new Runnable(){
   @Override
   public void run() {
    for(int i=0;i<10000;i++){
     incByOne();
    }
   }   
  });  
  t1.start();
  t2.start();
  
  try {
   t1.join();
  
   t2.join();
  } catch (InterruptedException e) {
   e.printStackTrace();
  }  
  System.out.println("Count is: "+ number);
 }
}
In this we have created method incByOne() with synchronized  to increment the number by one and that will be called inside a thread.
Method marked as synchronized can only be called by only one thread at a time.so the accessing same variable at the same time by two threads won't be happened.

This happens because every object in java has a intrinsic lock or a monitor lock also called a mutex. If a thread calls synchronized method of a object, (In this case synchronized method of App object) that thread has acquire  the intrinsic lock of that object. If another thread want to call that synchronized method it has to wait until the first thread releases the intrinsic lock.

No comments:

Post a Comment

Optimize you working enviorenment : Single command to create & move to a directory in linux (C Shell, Bash)

Usually move to a directory just after creating is bit of a anxious task specially if the directory name is too long. mkdir long-name-of...