SYNCHRONIZATION

Synchronization


When two or more threads need access to a shared resource, they need some way to ensure that the resource will be used only by one thread at a time. The process by which this is ensured is called Synchronization. Key to synchronization is the concept of the monitor (also called Semaphore). A monitor is an object that is used as a mutually exclusive lock, or mutex. Only one thread can own a monitor at a given time. When a thread acquires a lock, it is said to have entered the monitor. All other threads attempting to enter the locked monitor will be suspended until the first thread exits the monitor. A thread that owns a monitor can reenter the same monitor if it so desires. There are two ways to synchronize your code:

Naming Convention
Synchronization


Using synchronized methods:

Synchronizing is easy in Java because all objects have their own monitor associated with them. To enter an object’s monitor, just call a method that has been modified with the synchronized keyword. While a thread is inside a synchronized method, all other threads that try to call it (or any other synchronized method) on the same instance have to wait. To exit the monitor and relinquish control of the object to the next waiting thread, the owner of the monitor simply returns from the synchronized method.

  1. When there is no synchronization, nothing exists to stop all the threads from calling the same method on the same object at the same time. This is known as a race condition, because the threads are vying with each other to complete the method. In most situations, a race condition is less predictable, because you cannot be sure when the context switch will occur. This can cause a program to run right one time and wrong the next.

  2. To fix this problem you must serialize access to a method. That is, you must restrict its access to only one thread at a time. To do this, qualify the method with ‘synchronized’ keyword. Anytime that you have a method, or a group of methods that manipulate the internal state of an object in a multi-threaded situation, you should use the ‘synchronized’ keyword to guard the state from race conditions. Once a thread enters any synchronized method on an instance, no other thread can enter any other synchronized method on the same instance. However, non- synchronized method on that instance will continue to be callable.

  3. The synchronized statement

  4. If you want to synchronize access to objects of a class that was not designed for multi-threaded access i.e. the class does not use synchronized methods or if you do not access to the source code of the class, then simply put calls to the methods defined by this class inside a synchronized block

  5. synchronized ( object){
    // statements to be synchronized.
    }

  6. Here object is a reference to the object being synchronized. If you want to synchronize only a single statement, curly braces are not needed. A synchronized block ensures that a call to a method that is a member of object occurs only after the current thread has successfully entered object’s monitor.

  7. Inter-thread communication: Multithreading replaces event loop programming by dividing your tasks into discreet and logical units. Threads also provide a secondary benefit: they do away with polling. Polling is usually implemented by a loop that is used to check some condition repeatedly. Once the condition is true, appropriate action is taken. This wastes CPU time.To avoid polling, Java includes an elegant inter-process communication via wait(), notify() and notifyAll(). These methods are implemented as final methods in Object, so all classes have them. All these three methods can be called only from within a synchronized method.

  8. The method wait() tells the calling thread to give up the monitor and go to sleep until some other thread enters the monitor and calls notify(). Additional forms of wait() exist that allow you to specify a period of time to wait.

  9. The method notify() wakes up the first thread that called wait() on the same object. The method notifyAll() wakes up all the threads that called wait() on the same object. The highest priority thread will run first.


In order to avoid data corruption due to multi threading on same object, sun people came up with new concept “synchronization”. Through synchronization, it is a process that provides lock to the object or class.


  • Once if we keep object lock only one thread can access at a time until unless current thread releases the object lock the other thread can’t get permission to access that corresponding object ,means one object can have only one object lock

  • In java we have two types of locks.

    • Object lock
    • Class lock

  • Object lock:

    If we want to secure non static attributes or instance attributes that are specific to object i.e. object lock. Through synchronized keyword we can get object lock or keep lock to the object.

  • Class lock:

    If we want to secure static information or static attributes we should go for class lock. In java we can keep lock to the class through static synchronized. Through Synchronized keyword we can only use for methods and blocks. We can’t use for attributes, and local variables.

Example 1:


        
               package com.sdj.pack1;
               class ObjPersn
               {
                  int age;
                  String name;
                  synchronized void setObjPersn(int age,String name)
                  {
                     this.age=age;
                     this.name=name;
                  }
                  public String toString()
                  {
                     return"name:"+name+"::age::"+age;}
                  }
                  class Thrd1 extendsThread
                  {
                     ObjPersn p;
                     public void run()
                     {
                        p.setObjPersn(23, "measum");
                     }
                     public Thrd1(ObjPersn p1) 
                     {
                        p=p1;
                     }
                  }
                  class Thrd2 extends Thread
                  {
                     ObjPersn p;
                     public void run()
                     {
                        p.setObjPersn(22, "jayaram");
                     }
                     public Thrd2(ObjPersn p1) 
                     {
                        p=p1;   
                     }
                  }
                  public class ThSynch 
                  {
                     public static void main(String afd[])
                     {
                        ObjPersn p=new ObjPersn();
                        p.setObjPersn(24, "sankar");
                        Thrd1 t=new Thrd1(p);
                        Thrd2 t1=new Thrd2(p);
                        t.start();
                        t1.start();
                        System.out.println(p.toString());
                        System.out.println(t.p);
                        System.out.println(t1.p);
                     }
                  }
               }        

   Output:

name:measum::age::23 name:jayaram::age::22 name:jayaram::age::22


Example 2:


        package com.sdj.pack1;
               class ThSaf extendsThread
               {
                  NumberPrinter np;
                  ThSaf(NumberPrinter p)
                  {
                     np=p;   
                  }
                  public void run()
                  {
                     np.printNumber();
                  }
               }
               class NumberPrinter
               {
                  void printNumber()
                  {
                     for(int i=0;i<20;i++)
                     {
                        System.out.print(Thread.currentThread().getName()+"::"+i);
                        if(i%10==0)
                        {
                           try
                           {
                              Thread.sleep(3000);
                           }
                           catch(InterruptedException e){}
                        }
                     }
                  }
               }
               public class ThreadSafety 
               {
                  public static void main(String[] args) 
                  {
                     NumberPrinter p=new NumberPrinter();
                     ThSaf t=new ThSaf(p);
                     ThSaf t1=new ThSaf(p);
                     t.start();
                     t1.start();
                     t.setName("sdj");
                     t1.setName("java");
                  }
               }        

   Output:

sdj::0 java::0 java::1 sdj::1 sdj::2 java::2 java::3 java::4 java::5 java::6 java::7 java::8 java::9
java::10 sdj::3 sdj::4 sdj::5 sdj::6 sdj::7 sdj::8 sdj::9 sdj::10 java::11 java::12 java::13 java::14
java::15 java::16 java::17 java::18 java::19 sdj::11 sdj::12 sdj::13 sdj::14 sdj::15 sdj::16 sdj::17
sdj::18 sdj::19

Explanation:

Here we are getting two thread outputs simultaneously why because we are not using any locking concept or not following thread safety. If we provide object printNumber() method means.

i.e.
synchronized void printNumber()
{
    for(int i=0;i<20;i++)
       {
             System.out.println(Thread.currentThread().getName()+"::"+i);
              if(i%10==0)
              {
                  try
                    {
                     Thread.sleep(3000);
                      }
                 catch(InterruptedException e)
                 {
                 }
             }
        }
}


Example 3:


        
               package com.sdj.pack1;
               class Aa extends Thread
               {        synchronizedvoid test1()
                  {    System.out.println(Thread.currentThread().getName()+"in test1");
                     try
                     { sleep(200); }
                     catch(InterruptedException e)
                     {e.printStackTrace();}
                     test2();
                     test3();
                     System.out.println("test1 end");
                  }
                  synchronizedvoid test2()
                  {   System.out.println(Thread.currentThread().getName()+"in test2");
                     test3();   }
                  void test3()
                  {   System.out.println(Thread.currentThread().getName()+"in test3");}
               }
               class Synch1 extends Thread
               {
                  Aa a;
                  Synch1(Aa a)
                  {
                     a=a;
                  }
                  public void run()
                  {
                     a.test1();
                     System.out.println(getName()+" end");
                  }
               }
               class Synch2 extends Thread 
               {
                  Aa a;
                  public Synch2(Aa a) 
                  {
                     this.a=a;
                  }
                  public void run()
                  {
                     a.test2();
                     System.out.println(getName()+" end");
                  }
               }
               public class ThSynch1 
               {
                  public static void main(String[] args) 
                  {
                     Aa a=new Aa();
                     Synch1 t1=new Synch1(a);
                     Synch2 t2=new Synch2(a);
                     t1.start();
                     t2.start();
                     a.test3();
                     a.test2();
                     System.out.println("main end");
                  }
               }        

   Output

Thread 0 in test1 Main in test3 (this statement execute without object lock because it is not synchronized method) Thread 0 in test2 Thread 0 in test3 Thread 0 in test3 Test1 end

Explanation:

  • Here it releases object lock

  • But here two threads are waiting to get object lock i.e. main and thread1

  • If main thread get object lock then execution continues

    • Main in test2
    • Main in test3
  • Then after release object lock for thread 1 it starts execution

    • Thread 1 in test2
    • Thread 1 in test3
    • Thread 1 end
  • Releases object lock and go to death state

    • Main end
  • Main go to death state