synchronization:

  • synchronized is the modifier applicable only for the methods and blocks but not for classes and variables.
  • If multiple Threads are trying to operate simultaneously on the same java object, then they may be a chance of Data in-consistency problem.
  • To overcome this problem, we should go for synchronized keyword.
  • If a method or block declared as synchronized then at a time only one Thread is allowed to execute that method or block on the given object. So that data in-consistency problem will be resolved.

The main advantage of synchronized keyword is we can resolve data in-consistency problems but the main disadvantage of synchronized keyword is it increases waiting time of Threads and creates performance problems. Hence if there is no specific requirement then it is not recommended to use synchronized keyword.

  • Internally synchronization concept is implemented by using lock. Every object in java has a unique lock.
  • Whenever we are using synchronized keyword then only lock concept will come into the picture.
  • If a Thread wants to execute synchronized method on the given object first it has to get lock of that object.
  • Once Thread got the lock then it allowed to execute any synchronized method on that object.
  • Once Method execution completed automatically Thread releases that lock.
  • Acquiring and releasing lock internally takes care by JVM and programmer not responsible for this activity.
  • While a Thread executing synchronized method on the given object, the remaining Threads are not allowed to execute any synchronized method simultaneously on the same object. But remaining Threads are allowed to execute non-synchronized methods simultaneously
class X    
    synchronized m1()
    synchronized m2()
    m3()
}
synchronized

lock concept is implemented based on the object but not based on method.

syncandnonsync
class ReservationSystem{
    non-synchronized checkAvailability{
        ………………
        ………………
        Just read operation
        ………………
        ………………
    }
    synchronized bookTicket(){
        ………………
        ……………… 
        Update
        ………………
        ………………
    }
}
class Display{
    public void wish(String name){
        for(int i = 0; i < 5; i++){
            System.out.println("Good Morning :");
            try{
               Thread.sleep(2000);
            }
            catch(InterruptedException e){
            }
            System.out.println(name);
        }
    }
}
class MyThread extends Thread{
    Display d;
    String name;
    MyThread(Display dString name){
        this.d = d;
        this.name = name;
    }
    public void run(){
        d.wish(name);
    }
}
class SynchronizedDemo{
    public static void main(String[] args){
        Display d = new Display();
        MyThread t1 = new MyThread(d, "Dhoni");
        MyThread t2 = new MyThread(d, "Rohit");
        t1.start(); 
        t2.start();
    }
}

If we are not declaring wish() method as synchronized then both Threads will executed simultaneously and hence we will get irregular outputs.

Good morning : Dhoni
Good morning : Dhoni
Good morning : Rohit
Good morning : Dhoni
Good morning : Rohit
Good morning : Rohit
Good morning : Dhoni
Good morning : Rohit
Good morning : Dhoni
Good morning : Rohit

class Display{
    public void wish(String name){
        for(int i = 0; i < 5; i++){
            System.out.println("Good Morning :");
            try{
                Thread.sleep(2000);
            }
            catch(InterruptedException e){ 
            }
            System.out.println(name);
        }
    }
}
class MyThread extends Thread{
    Display d;
    String name;
    MyThread(Display dString name){
        this.d = d;
        this.name = name;
    }
    public void run(){
        d.wish(name);
    }
}
class SynchronizedDemo{
    public static void main(String[] args){
        Display d = new Display();
        MyThread t1 = new MyThread(d, "Dhoni");
        MyThread t2 = new MyThread(d, "Rohit");
        t1.start();
        t2.start();
    }
}

If we are declaring wish() method as synchronized then at a time only one Thread is allowed to execute wish() method on given Display object and hence we will get regular output.

Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit

Case study:
Even though wish() method is synchronized we will get irregular output because Threads are operating on different java objects.
Reason: If multiple Threads are operating on same java object then synchronization is required if multiple Threads are operating on multiple java objects then synchronization is not required.

class Display{
    public synchronized void wish(String name){
        for(int i = 0; i < 5; i++){
            System.out.println("Good Morning :");
            try{
                Thread.sleep(2000);
            }
            catch(InterruptedException e){
            }
            System.out.println(name);
        }
    }
}
class MyThread extends Thread{
    Display d;
    String name;
    MyThread(Display dString name){
        this.d = d;
        this.name = name;
    }
    public void run(){
        d.wish(name);
    }
}
class SynchronizedDemo{
    public static void main(String[] args){
        Display d1 = new Display();
        Display d2 = new Display();
        MyThread t1 = new MyThread(d1, "Dhoni");
        MyThread t2 = new MyThread(d2, "Rohit");
        t1.start();
        t2.start();
    }
}
displayObject

Class-level-lock:

  • Every class in java has a unique lock which is nothing but class-level-lock.
  • If a Thread wants to execute a static synchronized method, then Thread required class-level-lock.
  • Once Thread got class level lock then it is allowed to execute any static synchronized method of that class.
  • Once method execution completed automatically Thread releases the lock.
ClassLevelLock

While a Thread executing static synchronized method the remaining Threads are not allowed to execute an static synchronized method of that class simultaneously but remaining Threads are allowed to execute the following methods simultaneously.
1. normal static methods
2. synchronized instance methods
3. normal instance methods

class MyClass{
    static synchronized m1(){}
    static synchronized m2(){}
    static m3(){}
    synchronized m4(){}
    m5(){}
objectLevelLock
class Display{
    public synchronized void displayNumbers(){
        for(int i = 1; i <= 10; i++){
            System.out.print(i);
            try{
                Thread.sleep(2000);
            }
            catch(InterruptedException e){
          }
    }
    }
    public synchronized void displayCharacters(){
        for(int i = 65; i <= 75; i++){
            System.out.print(i);
            try{
                Thread.sleep(2000);
            }
            catch(InterruptedException e){
            }
        }
    }
}
class MyThread1 extends Thread{
    Display d;
    MyThread1(Display d){
        this.d = d;
    }
    public void run(){
        d.displayNumbers();
    }
}
class MyThread2 extends Thread{
    Display d;
    MyThread2(Display d){
        this.d = d;
    }
    public void run(){
        d.displayCharacters();
    }
}
class SynchronizedDemo{
    public static void main(String[] args){
        Display d = new Display();
        MyThread1 t1 = new MyThread1(d);
        MyThread2 t2 = new MyThread2(d); 
        t1.start();
        t2.start();
    }
}

Output:
12345678910ABCDEFGHIJK

displayObject

synchronized block:

If very few liners of the code require synchronization, then it is not recommended to declare entire method ass synchronization, we have to enclosed those few lines of the code by using synchronized block.

The main advantage of synchronized block over synchronized method is, it reduces waiting time of thread and improves performance of the system.

we can declare synchronized block as follows

1. To get lock of current object:

synchronized(this){
    .......
    If a Thread got lock of current object, then only it is allowed to execute this area
    .......
}

2. To get lock of particular object:

synchronized(b){
    ......
    If a Thread got lock of particular object 'b' then only it is allowed to execute this area.
    ......
}

3. To get lock of class-level-lock:

synchronized(Display.class){
    .....
    If a Thread got class-level-lock of 'Display' class, then only it is allowed to execute this area.
    .....
}
class Display{
    public void wish(String name){
        ;;;;;;;// n- number of line sof code
        synchronized(this){
            for(int i = 0; i < 5; i++){
                System.out.println("Good Morning :");
                try{
                   Thread.sleep(2000);
                }
                catch(InterruptedException e){
                }
                System.out.println(name);
            }
        }
        ;;;;;;;// n- number of line of code
    }
}
class MyThread extends Thread{
    Display d;
    String name;
    MyThread(Display dString name){
        this.d = d;
        this.name = name;
    }
    public void run(){
        d.wish(name);
    }
}
class SynchronizedDemo{
    public static void main(String[] args){
        Display d = new Display();
        MyThread t1 = new MyThread(d, "Dhoni");
        MyThread t2 = new MyThread(d, "Rohit");
        t1.start();
        t2.start();
    }
}

Output:
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit




//class-level-lockclass Display{
    public void wish(String name){
        ;;;;;;;// n- number of line sof code
        synchronized(Display.class){
            for(int i = 0; i < 5; i++){
                System.out.println("Good Morning :");
                try{
                    Thread.sleep(2000);
                }
                catch(InterruptedException e){
                }
                System.out.println(name);
            }
        }
        ;;;;;;;// n- number of line of code
    }
}
class MyThread extends Thread{
    Display d;
    String name;
    MyThread(Display dString name){
        this.d = d;
        this.name = name;
    }
    public void run(){
        d.wish(name);
    }
}
class SynchronizedDemo{
    public static void main(String[] args){
        Display d1 = new Display();
        Display d2 = new Display();
        MyThread t1 = new MyThread(d1, "Dhoni");
        MyThread t2 = new MyThread(d2, "Rohit");
        t1.start();
        t2.start();
    }
}

Output:
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Dhoni
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit
Good morning : Rohit

lock concept is applicable to object types and class types but not for primitives. Hence, we can’t pass primitive type as argument to synchronized block. Otherwise, we will get compile time error saying Unexpected type found: int required: reference


class Display{
    public void wish(String name){
        ;;;;;;;// n- number of line sof code
        int x = 10;
        synchronized(x){
            for(int i = 0; i < 5; i++){
                System.out.println("Good Morning :");
                try{
                    Thread.sleep(2000);
                }
                catch(InterruptedException e){
                }
                System.out.println(name);
            }
        } 
        ;;;;;;;// n- number of line of code
    }
}
class MyThread extends Thread{
    Display d;
    String name;
    MyThread(Display dString name){
        this.d = d;
        this.name = name;
    }
    public void run(){
        d.wish(name);
    }
}
class SynchronizedDemo{
    public static void main(String[] args){
        Display d = new Display();
        MyThread t1 = new MyThread(d, "Dhoni");
        MyThread t2 = new MyThread(d, "Rohit");
        t1.start();
        t2.start();
    }
}


Is a Thread can acquire multiple locks simultaneously?

Ans: YES, of course from different objects.

class X{\
    public synchronized void m1(){
        //Here Thread has locks of 'X' object
        Y y = new Y();
        synchronized(y){
            //Here Thread has locks of 'X' and 'Y' object
            Z z = new Z();
            synchronized(z){
                //Here Thread has locks of 'X', 'Y', 'Z' object
            }
        }
    }
}
class Main{
    public static void main(String[] args){
        X x = new X();
        x.m1();
    }
}