Monday, December 26, 2016

How can we achieve synchronization in multi threaded environment in java

When all threads are sharing some common resource, then there might be possibility of data loss, overwrite etc. when one object is shared between multiple threads, in such case there should be a process which ensures that when one thread is accessing a shared resource then another thread should not be allowed to access it. This process is known as synchronization.

In java, every object holds an implicit lock which is called Monitor.




This situation occurs in web based and distributed applications.

package dev21century.threading;

public class Thread1 {
       int xyresult;

       int add(int a, int b)
       {
              x = a;
              y = b;
              result = x + y;
              return result;
       }
}

Thread1 calls above method with 10, 20
Thread2 calls above method with 30, 40
Thread3 calls above method with 50, 60

There are 2 ways of implementing synchronization – one is to synchronize whole method and another is to synchronize a particular block.
Example
synchronized int add(int a, int b) {  }
Or
Synchronized {
//block code
}

Rule – if a thread is entering in a synchronized method or a synchronized block for a particular object then that thread must have the monitor (lock) of that object. So, when thread1 starts, it takes the lock first and then run, and if by chance while executing it went to the blocked state then it will take the lock with it. Now, when another thread enters with same object then obviously it cannot acquire the lock of that object and will not able to run and will wait until the first thread is completed to take the lock of the object.
So, this way we can stop data corruption.

Example:
Create a file RunSync.java in dev21century.threading package:
package dev21century.threading;

class Shared
{
  int x;
  synchronized void show(String s, int a)
  {
     x = a;
     System.out.println("Entered in method " + s + " " + x);
     try{
         Thread.sleep(2000);
        }
     catch(Exception e)
     {
     System.out.println(e);
     }
     System.out.println("Exit from method " + s + " " + x);
  }
}

class CustomThread1 extends Thread
{
       Shared s;
       CustomThread1(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 10);
       }
}

class CustomThread2 extends Thread
{
       Shared s;
       CustomThread2(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 20);
       }
}

class CustomThread3 extends Thread
{
       Shared s;
       CustomThread3(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 30);
       }
}

public class RunSync {

   public static void main(String[] args) {
      Shared st = new Shared();
      new CustomThread1(st, "one");
      new CustomThread2(st, "two");
      new CustomThread3(st, "three");
    }
}

Output:


In above example you will notice that each "Entered in..." message will be printed in a gap of 2 seconds. This is because when one thread enters the show method it will first take the lock of shared object, will print message and sleep for 2 seconds, and as the show method is synchronized, that means no other thread can enter this method with same object for at least 2 seconds that’s why it takes 2 seconds for next message.

Now, just remove synchronized keyword and try once again, this time all 3 messages will be printed without waiting. So this is the beauty of synchronization.

Quick Question – if we have 2 methods synchronized then will the second thread call the second thread?
Answer – it will never allow calling second method as well because lock is at object level, and same object is getting passed for both methods (if we will remove “synchronized” then second method will be invoked.

Rule – the implicit lock (monitor) is also maintained at class level. In case of non static methods, the object lock is used, but in case of static methods the class level lock is used.

If one method is called through class and another through Object, then the lock will always be checked for class if using static method.

If one method is static and another is non static then both will run separately with class and object level locks.

Synchronized block:
In java we can make a block as synchronized instead of synchronizing complete method. This is beneficial because synchronizing a method may degrade the performance because, all statements that are not participating in multithreading will also be locked.

Syntax:
public void show()
{
synchronized (this)
{
            //code which needs synchronization
}

//code which does not need synchronization
}

In case of synchronized method, the lock is always acquired on current object, but in case of synchronized block the lock can be acquired on any object.

synchronized block is also used to make the object of any class synchronized, by default objects are not synchronized, but we can synchronize it by using synchronized block.

lets modify our existing program as follows:

package dev21century.threading;

class Shared
{
 int x;
 void show(String s, int a)
 {
  System.out.println("Entered in method " + s);
  synchronized(this)
  {
   x = a;
   System.out.println("Entered in synchronized block " + s +" " + x);
      
   try {
       Thread.sleep(2000);
       }
   catch (InterruptedException e) {
        System.out.println(e);
   }
   System.out.println("Exit from synchronized block " + s +" " + x);
      
  }
 }
}

class CustomThread1 extends Thread
{
       Shared s;
       CustomThread1(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 10);
       }
}

class CustomThread2 extends Thread
{
       Shared s;
       CustomThread2(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 20);
       }
}

class CustomThread3 extends Thread
{
       Shared s;
       CustomThread3(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 30);
       }
}

public class RunSync {
 public static void main(String[] args) {
  Shared st = new Shared();
  new CustomThread1(st, "one");
  new CustomThread2(st, "two");
  new CustomThread3(st, "three");
 }
}

Output:

Now, in this example you will notice that all “Entered in method” messages will be printed without any wait, but “Entered in synchronized block…” messages will be printed with 2 seconds gap because they are in synchronized block, and without printing “Exit..” message the next “Entered in sync block..” message is not getting displayed. It means no threads are allowed in synchronized block unless the current thread is completed properly.


Now, lets understand how we can achieve this noncurrent:
In above example we have synchronized the current object, but many times in development we face the situation where we need to synchronize other objects as well. So lets modify our program as follows, here we have created a new class called Temp and tried to synchronize it from outside:

package dev21century.threading;
class Temp
{
     void display(String s)
     {
           System.out.println("Entered in display Method.."+ s);
           try {
                Thread.sleep(2000);
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
           System.out.println("Exit from display method.." + s);
     }
}

class Shared
{
  int x;
  Temp temp = new Temp();
  void show(String s, int a)
  {
       System.out.println("Entered in show method " + s);
       synchronized(temp)
       {
        temp.display(s);
        try {
              Thread.sleep(2000);
        } catch (InterruptedException e) {
              System.out.println("Exit from synchronized block " + s + " " + x);
        }
       
       }
  }
}

class CustomThread1 extends Thread
{
       Shared s;
       CustomThread1(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 10);
       }
}

class CustomThread2 extends Thread
{
       Shared s;
       CustomThread2(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 20);
       }
}

class CustomThread3 extends Thread
{
       Shared s;
       CustomThread3(Shared s, String str)
       {
              super(str);
              this.s = s;
              start();
       }
       public void run()
       {
              s.show(Thread.currentThread().getName(), 30);
       }
}

public class RunSync {

   public static void main(String[] args) {
      Shared st = new Shared();
      new CustomThread1(st, "one");
      new CustomThread2(st, "two");
      new CustomThread3(st, "three");
    }
}

Output:

Quick Question – why suspend() and resume() are deprecated?
Answer – the suspend() method puts the thread in blocked pool infinitely and resume() brings it back. The problem is when a thread is suspended by suspend() method, it will take the lock with it, and in case if no one calls the resume() method then another thread can never enter that block. It will be a dead lock situation.

The alternate of suspend() and resume() is wait() and notify() both these methods belongs to Object classThe wait() method will acquire the lock and put thread in blocked pool.

notify() method will pull the thread from blocked pool which was blocked by wait() method.

Lets take this example:

package dev21century.threading;

class Shared
{
     int flag = 0;
     int data = 0;
     synchronized public void submit()
     {
           flag = 1;
           try {
                Thread.sleep(1000);
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
           data = 10;
           System.out.println("value submitted");
           notify();
     }
     synchronized int withdraw()
     {
           if(flag == 0)
           {
                try {
                     System.out.println("wait block");
                     wait();
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
           }
           return (data);
     }
    
}

class Thread1 extends Thread
{
     Shared s;
     Thread1(Shared s, String str)
     {
           super(str);
           this.s=s;
           start();
     }
     public void run()
     {
           System.out.println("data = " + s.withdraw());
     }
}

class Thread2 extends Thread
{
     Shared s;
     Thread2(Shared s, String str)
     {
           super(str);
           this.s=s;
           start();
     }
     public void run()
     {
           //System.out.println("data = " + s.withdraw());
           s.submit();
     }
}

public class RunSync {

   public static void main(String[] args) {
       
        Shared sharedObj = new Shared();
        new Thread1(sharedObj, "one");
        new Thread2(sharedObj, "two");
    }
}

Output:



There is another deadlock condition which might occur, so we should always avoid such kinds of programming, lets see this example:

package dev21century.threading;
class Temp
{
     void display(String s)
     {
           System.out.println("Entered in display Method.." + s);
           System.out.println("Exit from display method.." + s);
     }
}

class CustomThread1 extends Thread
{
       Temp t1t2;
       CustomThread1(Temp t1, Temp t2, String str)
       {
              super(str);
              this.t1 = t1;
              this.t2 = t2;
              start();
       }
       public void run()
       {
       synchronized(t1)
       {
              try {
                     Thread.sleep(2000);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
                t1.display(Thread.currentThread().getName());
                synchronized(t2)
                {
                    t2.display(Thread.currentThread().getName());
                }

       }
       }
}

class CustomThread2 extends Thread
{
       Temp t1t2;
       CustomThread2(Temp t1,Temp t2, String str)
       {
              super(str);
              this.t1 = t1;
              this.t2 = t2;
              start();
       }
       public void run()
       {
       synchronized(t2)
       {
              try {
                     Thread.sleep(1000);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
              t2.display(Thread.currentThread().getName());
                synchronized(t1)
                {
                    t1.display(Thread.currentThread().getName());
                }
       }
       }
}


public class RunSync {

   public static void main(String[] args) {
      Temp temp1 = new Temp();
      Temp temp2 = new Temp();
     
      new CustomThread1(temp1, temp2, "one");
      new CustomThread2(temp1, temp2, "two");
    }
}
  
As soon as you will run this program, it will print following output and will go to dead lock.


You will have to explicitly stop the program. This is because in this program the thread 1 has synchronized object 1 and thread 2 has synchronized the object 2. Hence both are waiting for each other. Always avoid such type of programming.

interrupt() method:
this is a Thread class method which is used to request to the JVM to terminate a thread. As we cannot force JVM for garbage collection, we can only request by using System.gc() method, similarly we cannot force JVM to terminate a thread. We can only request. In each class there is boolean flag which is set to true if interrupt request has been raised. In 99% cases JVM does not terminate the thread,

InterruptedException:
This exception is thrown when a thread is in sleep mode and interrupted by another thread. Lets understand this by an example:

create a java file Interrupt.java in dev21century.threading package:

package dev21century.threading;
class Thread1 extends Thread
{
     Thread1(String s)
     {
           super(s);
     }
     public void run()
     {
           System.out.println("Thread Name: " + getName());
           try{
                Thread.sleep(60000 * 10);
           }catch(Exception e)
           {}
           System.out.println("interrupted from class");
           System.out.println("Thread " + getName() + " dead..");
     }
}

class Thread2 extends Thread
{
     Thread1 thread1;
     Thread2(String s, Thread1 thread1)
     {
           super(s);
           this.thread1 = thread1;
     }
     public void run()
     {
           System.out.println("Thread Name  : " + getName());
           thread1.interrupt();
           try{
                Thread.sleep(1000);
           }catch(Exception e) {}
          
           System.out.println("Thread   : " + getName() + " dead.");
     }
}

public class Interrupt {
     public static void main(String args[])
     {
           Thread1 thread1 = new Thread1("thread1");
           thread1.setPriority(10);
           Thread2 thread2 = new Thread2("thread1", thread1);
           thread1.start();
           thread2.start();
          
          
     }
}
Output:

Shutdown hookup:
While terminating a program a thread can be invoked, such threads are called shutdown hookup. In this thread we can put some closing codes like closing database or network connection, taking backup etc.

Create a java file ShutdownHooksImpl.java in dev21century.threading package:

package dev21century.threading;

class ShutdownHooks implements Runnable
{
     public void run()
     {
           System.out.println("-- shutdown hookup started..");
           System.out.println("-- Application shutting down..");
           try{
                Thread.sleep(1000*5);
           }
           catch(Exception e)
           {
                System.out.println(e);
           }
     }
}

public class ShutdownHooksImpl {
 public static void main(String args[])
 {
     Runtime runTime = Runtime.getRuntime();
     ShutdownHooks hooks = new ShutdownHooks();
     //Register the shutdown hooks
     runTime.addShutdownHook(new Thread(hooks));
     int x =  100 / 0;
 }
}

Output:
In this program an exception occurred during program execution, even then the shutdown hookup thread got executed.

Task scheduling:
This is out of threading concept, threading is not used here. When you will run this example after a delay of 5 seconds a message will be printed in every 1 second:

Create a java file TaskScheduling.java in dev21century.threading package:
package dev21century.threading;

import java.awt.Frame;
import java.util.Timer;
import java.util.TimerTask;
class Task extends TimerTask
{
     int count = 1;
     /*run() is an abstract method
      which defines the task to be executed in scheduled
      interval */
     public void run() {
           System.out.println("Message from timer..");
     }
}

public class TaskScheduling {
     public static void main(String[] args) {

           Timer timer = new Timer();
           int delay = 5000; // 5 seconds
           int period = 1000; //repeate every seconds
           timer.scheduleAtFixedRate(new Task(), delay, period);
          
     }
}

Output:

Daemon Thread:
Following characteristics defines the daemon threads:
  1. Daemon threads are service provider threads, they provide services to other threads.
  2. These threads dead automatically if the thread to which they are providing service are dead.
  3. These threads never show any output.
  4. They always run in background.

For example assume a scenario where a client side thread needs to display an image, now here some should be there who brings the image from server / database. So, in this case just create a server side daemon thread which will bring image from the server database.
A real example if daemon thread is relay fielding in cricket match, where one man throws the ball to another and he it throws further.

Java’s garbage collector thread is a daemon thread.

There is a method setDaemon(Boolean) to make a thread as a daemon thread.
For example:

package dev21century.threading;
class DThread1 extends Thread
{     
       DThread1(String threadName)
       {
              super(threadName);
       }
       public void run()
       {
         for(int i = 0;i<5;i++)
          {
           System.out.println("Thread Name: " + getName());
          }
       }
}

public class MainThread {

       public static void main(String[] args) {

        DThread1 dthread1 = new DThread1("DaemonThread1");
       
        dthread1.setDaemon(true);
        //marking this thread as a daemon thread
       
        dthread1.start();
            
        for(int i = 0;i<4;i++)
        {
          System.out.println(Thread.currentThread().getName());
        }            
     }

}

Output:
main
Thread Name: DaemonThread1
main
Thread Name: DaemonThread1
main
main
Thread Name: DaemonThread1
Thread Name: DaemonThread1
Thread Name: DaemonThread1

Try to run this program many times the output may be different.


ThreadGroup:
ThreagGroup is a class in java which is used to group the set of threads. In this way we can perform a common type of tasks to all threads at one shot like interrupting them all.
As a real example providing training to multiple students one by one for same course is not advisable, instead group them up and teach them in a class room only once.

Example:
package dev21century.threading;
//thread 1 class
class GThread1 implements Runnable
{
       //run method is the main code of thread
       public void run()
       {
         for(int i = 0;i<5;i++)
          {
           System.out.println("Thread Name: " + Thread.currentThread().getName());
          }
       }
}
//thread 2 class
class GThread2 implements Runnable
{
       public void run()
       {
        for(int i = 0;i<7;i++)
         {
          System.out.println("Thread Name: " + Thread.currentThread().getName());
         }
       }
}

//thread 3 class
class GThread3 implements Runnable
{
       public void run()
       {
        for(int i = 0;i<9;i++)
         {
          System.out.println("Thread Name: " + Thread.currentThread().getName());
         }
       }
}

public class MainThread {

       public static void main(String[] args) {

        ThreadGroup threadGroup = new ThreadGroup("MyThreadGroup");

        Thread gthread1 = new Thread(threadGroup, new GThread1());
        Thread gthread2 = new Thread(threadGroup, new GThread2());
        Thread gthread3 = new Thread(threadGroup, new GThread3());
       
        threadGroup.interrupt();
        /*with this statement, all 3 threads will
        be interrupetd at once.*/
       
        gthread1.start();
        gthread2.start();
        gthread3.start();

        for(int i = 0;i<11;i++)
        {
          System.out.println(Thread.currentThread().getName());
        }            
     }

}

Output:
main
main
Thread Name: Thread-2
Thread Name: Thread-2
Thread Name: Thread-2
Thread Name: Thread-2
Thread Name: Thread-1
Thread Name: Thread-2
main
Thread Name: Thread-0
main
Thread Name: Thread-2
Thread Name: Thread-1
Thread Name: Thread-2
main
Thread Name: Thread-0
main
Thread Name: Thread-2
Thread Name: Thread-1
Thread Name: Thread-2
main
main
main
main
Thread Name: Thread-0
main
Thread Name: Thread-1
Thread Name: Thread-1
Thread Name: Thread-1
Thread Name: Thread-1
Thread Name: Thread-0
Thread Name: Thread-0

No comments:

Post a Comment