Tuesday, August 2, 2016

Synchronization in Thread indepth

Synchronization in java is the capability to control the access of multiple threads to any shared resource.
Java Synchronization is better option where we want to allow only one thread to access the shared resource.

Why use Synchronization
The synchronization is mainly used to
  1. To prevent thread interference.
  2. To prevent consistency problem.
 There are two types of thread synchronization mutual exclusive and inter-thread communication.
  1. Mutual Exclusive
    1. Synchronized method.
    2. Synchronized block.
    3. static synchronization.
  2. Cooperation (Inter-thread communication in java)
 Mutual Exclusive
Mutual Exclusive helps keep threads from interfering with one another while sharing data. This can be done by three ways in java:
  1. by synchronized method
  2. by synchronized block
  3. by static synchronization
 When a method or block is declared as synchronized, only one thread can enter into that method or block. When one thread is executing synchronized method or block, the other threads which wants to execute that method or block wait or suspend their execution until first thread is done with that method or block. Thus avoiding the thread interference and achieving thread safeness. This can be explained well with the help of an example.

Consider this example,

class Shared
{
    int i;
     synchronized void SharedMethod()
    {
        Thread t = Thread.currentThread();
        for(i = 0; i <= 1000; i++)
        {
            System.out.println(t.getName()+" : "+i);
        }
    }
}

public class ThreadsInJava
{
    public static void main(String[] args)
    {
        final Shared s1 = new Shared();

        Thread t1 = new Thread("Thread - 1")
        {
            @Override
            public void run()
            {
                s1.SharedMethod();
            }
        };
        Thread t2 = new Thread("Thread - 2")
        {
            @Override
            public void run()
            {
                s1.SharedMethod();
            }
        };
        t1.start();
        t2.start();
    }
}
In the above example, both threads t1 and t2 wants to execute sharedMethod() of s1 object. But, sharedMethod() is declared as synchronized. So, whichever thread enters first into sharedMethod(), it continues to execute that method. The other thread waits for first thread to finish it’s execution of sharedMethod(). It never enters into sharedMethod() until first thread is done with that method. That means, both threads are executing sharedMethod() one by one not simultaneously. This protects the value of “i” in the memory for a particular thread.

The Logic Behind the Synchronization in Java:
The synchronization in java is built around an entity called object lock or monitor. Here is the brief description about lock or monitor.
·         Whenever an object is created to any class, an object lock is created and is stored inside the object.
·         One object will have only one object lock associated with it.
·         Any thread wants to enter into synchronized methods or blocks of any object, they must acquire object lock associated with that object and release the lock after they are done with the execution.
·         The other threads which wants to enter into synchronized methods of that object have to wait until the currently executing thread releases the object lock.
·         To enter into static synchronized methods or blocks, threads have to acquire class lock associated with that class as static members are stored inside the class memory.

Synchronized Blocks:

Sometimes, you need only some part of the method to be synchronized not the whole method. This can be achieved with synchronized blocks. Synchronized blocks must be defined inside a definition blocks like methods, constructors, static initializer or instance initializer.

synchronized block takes one argument and it is called mutex. if synchronized block is defined inside non-static definition blocks like non-static methods, instance initializer or constructors, then this mutex must be an instance of that class. If synchronized block is defined inside static definition blocks like static methods or static initializer, then this mutex must be like ClassName.class.

Here is an example of static and non-static synchronized blocks.

class Shared
{
    static void staticMethod()
    {
        synchronized (Shared.class)
        {
            //static synchronized block
        }
    }

     void NonStaticMethod()
    {
        synchronized (this)
        {
            //Non-static synchronized block
        }
    }

    void anotherNonStaticMethod()
    {
        synchronized (new Shared())
        {
            //Non-static synchronized block
        }
    }
}

10 Points-To-Remember About Synchronization In Java:

1) You can use synchronized keyword only with methods but not with variables, constructors, static initializer and instance initializers.
class Shared
{
    synchronized int i;    //compile time error, can't use synchronized keyword with variables

    synchronized public Shared()
    {
        //compile time error, constructors can not be synchronized
    }

    synchronized static
    {
        //Compile time error, Static initializer can not be synchronized
    }

    synchronized
    {
        //Compile time error, Instance initializer can not be synchronized
    }
}

2) Constructors, Static initializer and instance initializer can’t be declared with synchronized keyword, but they can contain synchronized blocks.
class Shared
{
    public Shared()
    {
        synchronized (this)
        {
            //synchronized block inside a constructor
        }
    }

    static
    {
        synchronized (Shared.class)
        {
            //synchronized block inside a static initializer
        }
    }

    {
        synchronized (this)
        {
            //synchronized block inside a instance initializer
        }
    }
}

3) Both static and non-static methods can use synchronized keyword. For static methods, thread need class level lock and for non-static methods, thread need object level lock.
class Shared
{
    synchronized static void staticMethod()
    {
        //static synchronized method
    }

    synchronized void NonStaticMethod()
    {
        //Non-static Synchronized method
    }
}

4) It is possible that both static synchronized and non-static synchronized methods can run simultaneously. Because, static methods need class level lock and non-static methods need object level lock.

5) A method can contain any number of synchronized blocks. This is like synchronizing multiple parts of a method.
class Shared
{
    static void staticMethod()
    {
        synchronized (Shared.class)
        {
            //static synchronized block - 1
        }

        synchronized (Shared.class)
        {
            //static synchronized block - 2
        }
    }

    void NonStaticMethod()
    {
        synchronized (this)
        {
            //Non-static Synchronized block - 1
        }

        synchronized (this)
        {
            //Non-static Synchronized block - 2
        }
    }
}

6) Synchronization blocks can be nested.
synchronized (this)
{
    synchronized (this)
    {
        //Nested synchronized blocks
    }
}
7) Lock acquired by the thread before executing a synchronized method or block must be released after the completion of execution, no matter whether execution is completed normally or abnormally (due to exceptions).

8) Synchronization in java is Re-entrant in nature. A thread can not acquire a lock that is owned by another thread. But, a thread can acquire a lock that it already owns. That means if a synchronized method gives a call to another synchronized method which needs same lock, then currently executing thread can directly enter into that method or block without acquiring the lock.

9) synchronized method or block is very slow. They decrease the performance of an application. So, special care need to be taken while using synchronization. Use synchronization only when you needed it the most.

10) Use synchronized blocks instead of synchronized methods. Because, synchronizing some part of a method improves the performance than synchronizing the whole method.

No comments:

Post a Comment