Categories: Java

Synchronization in Java

What is Synchronization, and why is it used?

Multiple threads trying to access the same resources in a multithreaded program may frequently result in unexpected and incorrect results. Therefore, it must be ensured through some form of synchronization that only one thread can access the resource at any given time.

  • Java offers a method for setting up threads and synchronizing their operations with the aid of synchronized blocks.
  • The synchronized keyword in Java is used to identify synchronized blocks. In Java, a synchronized block is one that is tied to an object.
  • Only one thread can be running at a time inside synchronized blocks since they are all synchronized on the same object.
  • Until the thread inside the synchronized block exits the block, all other threads trying to enter the block are blocked.
Syntax:
synchronized (object)
{
  //statement to be synchronized
}
Synchronized Java Method:
  • Any method is referred to as a synchronized method if you declare it to be so.
  • Locking an object for any shared resource involves using a synchronized method.
  • A thread automatically acquires the lock for an object when it calls a synchronized method, and it releases the lock once the thread has finished its work.
The problem without Synchronization:

The below example shows the Powers of the numbers like n1, n2, n3, n4or n5.

public class Power{  
   void printPower(int n){//method not synchronized
   int temp = 1;
   for(int i=1;i<=5;i++)
   { 
     System.out.println(Thread.currentThread().getName() + ":- " +n + "^"+ i + " value: " + n*temp);
     temp = n*temp;
     try
     {  
      Thread.sleep(500);  
     }
     catch(Exception e)
     {
         System.out.println(e);
         
     }  
   }  
 }  
}  
public class Thread1 extends Thread
{  
   Power p;  
   Thread1(Power p)
   {  
    this.p=p;  
  }  
 public void run()
 {  
   p.printPower(5);  
 }    
}  
public class Thread2 extends Thread
 {  
   Power p;  
   Thread2(Power p)
    {  
      this.p=p;  
    }  
  public void run()
  {  
    p.printPower(8);  
  }  
}  
  
public class Synchronization_Example1
 {  
  public static void main(String args[])
  {  
    Power obj = new Power();//only one object  
    Thread1 p1=new Thread1(obj);  
    Thread2 p2=new Thread2(obj);  
    p1.start();  
    p2.start();
 }  
}
Output:
Thread-1:- 8^1 value: 8

Thread-0:- 5^1 value: 5

Thread-1:- 8^2 value: 64

Thread-0:- 5^2 value: 25

Thread-1:- 8^3 value: 512

Thread-0:- 5^3 value: 125

Thread-1:- 8^4 value: 4096

Thread-0:- 5^4 value: 625

Thread-1:- 8^5 value: 32768

Thread-0:- 5^5 value: 3125
Above Example using Synchronized Method :
public class Power{  
   synchronized void printPower(int n){//method synchronized
   int temp = 1;
   for(int i=1;i<=5;i++)
   { 
     System.out.println(Thread.currentThread().getName() + ":- " +n + "^"+ i + " value: " + n*temp);
     temp = n*temp;
     try
     {  
      Thread.sleep(500);  
     }
     catch(Exception e)
     {
         System.out.println(e);
         
     }  
   }  
 }  
}  
public class Thread1 extends Thread
{  
   Power p;  
   Thread1(Power p)
   {  
    this.p=p;  
  }  
 public void run()
 {  
   p.printPower(5);  
 }    
}  
public class Thread2 extends Thread
 {  
   Power p;  
   Thread2(Power p)
    {  
      this.p=p;  
    }  
  public void run()
  {  
    p.printPower(8);  
  }  
}  
  
public class Synchronization_Example1
 {  
  public static void main(String args[])
  {  
    Power obj = new Power();//only one object  
    Thread1 p1=new Thread1(obj);  
    Thread2 p2=new Thread2(obj);  
    p1.start();  
    p2.start();
 }  
}
Output:
Thread-0:- 5^1 value: 5

Thread-0:- 5^2 value: 25

Thread-0:- 5^3 value: 125

Thread-0:- 5^4 value: 625

Thread-0:- 5^5 value: 3125

Thread-1:- 8^1 value: 8

Thread-1: – 8^2 value: 64

Thread-1:- 8^3 value: 512

Thread-1:- 8^4 value: 4096

Thread-1:- 8^5 value: 32768
Above Example using Synchronized Block :
public class Power
 {  
   void printPower(int n)
    { 
      synchronized(this)
      { //synchronized block
       int temp = 1;
       for(int i=1;i<=5;i++)
       { 
        System.out.println(Thread.currentThread().getName() + ":- " +n + "^"+ i + " value: " + n*temp);
        temp = n*temp;
       try
       {  
           Thread.sleep(500);  
       }
        catch(Exception e)
        { 
            System.out.println(e);
            
        }  
   }  
 }  
}  
}
  
public class Thread1 extends Thread
 {  
   Power p;  
   Thread1(Power p)
   {  
      this.p=p;  
   }  
  public void run()
  {  
    p.printPower(5);  
  }  
  
}  
public class Thread2 extends Thread
  {  
   Power p;  
   Thread2(Power p)
   {  
     this.p=p;  
   }  
   public void run()
   {  
     p.printPower(8);  
   }  
}  
  
public class Synchronization_Example3
{  
  public static void main(String args[])
  {  
    Power obj = new Power();//only one object  
    Thread1 p1=new Thread1(obj);  
    Thread2 p2=new Thread2(obj);  
    p1.start();  
    p2.start();

  }  
}
Output:
Thread-0:- 5^1 value: 5

Thread-0:- 5^2 value: 25

Thread-0:- 5^3 value: 125

Thread-0:- 5^4 value: 625

Thread-0:- 5^5 value: 3125

Thread-1:- 8^1 value: 8

Thread-1:- 8^2 value: 64

Thread-1:- 8^3 value: 512

Thread-1:- 8^4 value: 4096

Thread-1:- 8^5 value: 32768

Difference between synchronized method and block:
BasisSynchronized MethodSynchronized Block
Scope of lockSynchronized method does not reduce the scope of the lock.Synchronized block generally reduces the scope of the lock.
Control over the lockIf a synchronized method is static, it always locks either on the object currently represented by this keyword or a class-level lock.Synchronized blocks give you fine-grained control over a lock because any lock can be used to mutually exclude critical section code.
NullPointerExcpetionThe synchronized method does not throw java.lang.NullPointerException.Synchronized block can throw java.lang.NullPointerException if expression provided to block as parameter evaluates to null
Lock AcquisitionWhen a thread enters a synchronized method, it acquires the lock. When the thread exits the method, it can do so normally or by throwing an exception.
in the case of the synchronized block, the thread acquires a lock when they enter the synchronized block and release it when they leave the synchronized block.

Note: also read about the Daemon thread in Java

Follow Me

If you like my post, please follow me to read my latest post on programming and technology.

https://www.instagram.com/coderz.py/

https://www.facebook.com/coderz.py

Share
Published by
Rabecca Fatima

Recent Posts

Generate Parenthesis | Intuition + Code | Recursion Tree | Backtracking | Java

Problem Statement: Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. Example…

3 months ago

Square Root of Integer

Given an integer A. Compute and return the square root of A. If A is…

1 year ago

Build Array From Permutation

Given a zero-based permutation nums (0-indexed), build an array ans of the same length where…

1 year ago

DSA: Heap

A heap is a specialized tree-based data structure that satisfies the heap property. It is…

2 years ago

DSA: Trie

What is a Trie in DSA? A trie, often known as a prefix tree, is…

2 years ago

Trees: Lowest Common Ancestor

What is the Lowest Common Ancestor? In a tree, the lowest common ancestor (LCA) of…

2 years ago