Get free ebooK with 50 must do coding Question for Product Based Companies solved
Fill the details & get ebook over email
Thank You!
We have sent the Ebook on 50 Must Do Coding Questions for Product Based Companies Solved over your email. All the best!

Synchronization in Java

Java Synchronization is the technique provided by the JDK to assist developers in controlling the access the resources in an environment where more than one thread can access resources. Synchronization of resources is achieved by using java synchronized keyword. So, let us start with the definition of the topic.

What is Synchronization in Java?

Synchronization in Java is a mechanism used to control access to shared resources in a multi-threaded environment. The goal of synchronization is to ensure that only one thread can access a shared resource at a time, to prevent data corruption and inconsistent results caused by multiple threads accessing and modifying the same data simultaneously.

Java provides the synchronized keyword to implement synchronization. When a method or a block of code is marked as synchronized, it can only be accessed by one thread at a time. This is achieved by acquiring a lock on the object associated with the synchronized method or block.

Synchronization is an important concept in multi-threaded programming, as it ensures that shared data remains consistent and in a valid state, even in the presence of multiple threads accessing and modifying it simultaneously.

Types of Synchronization in Java

There are two types of synchronization in Java:

  • Method-Level Synchronization: In method-level synchronization, the entire method is marked as synchronized and can only be accessed by one thread at a time. This is achieved by acquiring a lock on the object associated with the method.
  • Block-Level Synchronization: In block-level synchronization, only a portion of the method is marked as synchronized. This is achieved by wrapping the portion of code that requires synchronization within a synchronized block and acquiring a lock on a specified object.

Both method-level and block-level synchronization can be used to control access to shared resources in a multi-threaded environment, but block-level synchronization provides more fine-grained control over the synchronization of a program. Block-level synchronization allows multiple threads to access different parts of a shared resource simultaneously, which can improve performance in certain cases.

Let us discuss both of these types of Synchronization in detail with the help of suitable examples.

Java Synchronized Method

In Java Programming Language, we can make any method as Synchronized Method by using the synchronized keyword. This is used to lock a particular object for any shared resource.

When a thread calls a java synchronized method, the lock for that object is automatically acquired and released when the thread completes its work.

Syntax for making Java Synchronized Method:

Acess_modifiers synchronized return_type method_name (Method_Parameters) {
    // Method Statements
}

Let us first see the problem that arises if there is no Synchronization.

class Table{  
    void printTable(int n){ 
        for(int i=1;i<=5;i++){  
    		System.out.println(n*i);  
     
    		try{  
    			Thread.sleep(400);  
    		}catch(Exception e){
    			System.out.println(e);
    		}  
        }  
    }  
}  
  
class MyThread1 extends Thread{  
    Table t;  
    MyThread1(Table t){  
        this.t=t;  
    }  

    public void run(){  
        t.printTable(5);  
    }  
}  

class MyThread2 extends Thread{  
    Table t;  
    MyThread2(Table t){  
        this.t=t;  
    }
    
    public void run(){  
        t.printTable(100);  
    }  
}  
  
class Main{  
    public static void main(String args[]){ 
        //shared object
        Table obj = new Table();  
        MyThread1 t1=new MyThread1(obj);  
        MyThread2 t2=new MyThread2(obj);  
        t1.start();  
        t2.start();  
    }  
}

Output:

5
100
10
200
15
300
20
400
25
500

Here, we have got inconsistent output, since the object of class “Table” is being modified by the two methods concurrently.

We can overcome this problem by using the synchronized method as shown in the code below:

class Table{  
    synchronized void printTable(int n){ 
        for(int i=1;i<=5;i++){  
    		System.out.println(n*i);  
     
    		try{  
    			Thread.sleep(400);  
    		}catch(Exception e){
    			System.out.println(e);
    		}  
        }  
    }  
}  
  
class MyThread1 extends Thread{  
    Table t;  
    MyThread1(Table t){  
        this.t=t;  
    }  

    public void run(){  
        t.printTable(5);  
    }  
}  

class MyThread2 extends Thread{  
    Table t;  
    MyThread2(Table t){  
        this.t=t;  
    }
    
    public void run(){  
        t.printTable(100);  
    }  
}  
  
class Main{  
    public static void main(String args[]){ 
        //shared object
        Table obj = new Table();  
        MyThread1 t1=new MyThread1(obj);  
        MyThread2 t2=new MyThread2(obj);  
        t1.start();  
        t2.start();  
    }  
}

Output:

5
10
15
20
25
100
200
300
400
500

Here, we have modified the method as “synchronized method”. This ensures that the object in use by one thread is not available for the second thread fro making changes.

Java Synchronized Block

The synchronized block can be used to perform synchronization on any method resource.

Suppose, we have 100 lines of code in our method but only want to synchronize 5 of them, we can use synchronized block. If we put all of the method’s codes in the synchronized block, it will work just like the synchronized method.

Syntax for writing Java Synchronized Block:

synchronized (object reference expression) {     
  //statements/methods    
} 

Let us see an example to use Java Synchronized Block.

class Table{  
    void printTable(int n){    
        synchronized(this){//synchronized block    
    		for(int i=1;i<=5;i++){    
    			System.out.println(n*i);    
      
    			try{    
    				Thread.sleep(400);    
    			}catch(Exception e){
    				System.out.println(e);
    			}    
    		}    
        }   // end of synchronized block 
    }//end of the method    
}    
  
class MyThread1 extends Thread{  
    Table t;  
    MyThread1(Table t){  
        this.t=t;  
    }  

    public void run(){  
        t.printTable(5);  
    }  
}  

class MyThread2 extends Thread{  
    Table t;  
    MyThread2(Table t){  
        this.t=t;  
    }
    
    public void run(){  
        t.printTable(100);  
    }  
}  
  
class Main{  
    public static void main(String args[]){ 
        //shared object
        Table obj = new Table();  
        MyThread1 t1=new MyThread1(obj);  
        MyThread2 t2=new MyThread2(obj);  
        t1.start();  
        t2.start();  
    }  
}

Output:

5
10
15
20
25
100
200
300
400
500

Here, instead of making the whole method synchronized, we have only made a particular block “synchronized”. The synchronized block also locks that particular block free from the updation by another thread.

Need for Synchronized Keyword in Java

The synchronized keyword in Java is used to control access to a shared resource in a multi-threaded environment. The need for synchronization arises because multiple threads can access and modify shared data simultaneously, leading to inconsistencies and data corruption.

The synchronized keyword is used to provide mutual exclusion, ensuring that only one thread can access the shared resource at a time. This ensures that the shared data remains consistent and in a valid state, even in a multi-threaded environment.

Additionally, java synchronized helps to prevent race conditions, and deadlocks, and improve performance in certain cases. It is used to ensure the proper functioning of multi-threaded programs and to ensure that shared data is not corrupted by multiple threads.

In short, the need for the synchronized keyword in Java arises from the requirement to control access to shared resources in a multi-threaded environment and to ensure that shared data remains consistent and in a valid state.

Advantages of Synchronization in Java

Some of the advantages of using Synchronization in Java include

  • Thread Safety: Synchronization in Java helps to achieve thread safety by ensuring that only one thread can access the shared resource at a time.
  • Consistency: Synchronization ensures that the shared data is consistent and remains in a valid state throughout the program.
  • Deadlock Prevention: By using synchronization, deadlocks can be prevented in a multi-threaded environment.
  • Avoid Race Conditions: Synchronization helps to avoid race conditions that can occur in a multi-threaded environment, where multiple threads try to access a shared resource simultaneously.
  • Improved Performance: Synchronization can also improve performance in certain cases, as it reduces the number of threads that are waiting for access to a shared re

Disadvantages of Synchronization in Java

Despite having several advantages, Synchronization in Java also have some disadvantages. These disadvantages are listed below:

  • Performance Overhead: Synchronization can increase the overhead of a program, as it requires the threads to wait for access to the shared resource, leading to a decrease in overall performance.
  • Deadlocks: Although synchronization can prevent deadlocks, it can also lead to deadlocks if not used correctly.
  • Starvation: Synchronization can lead to starvation, where a thread waiting for access to a shared resource is blocked indefinitely.
  • Reduced Concurrency: Synchronization reduces concurrency as it limits the number of threads that can access a shared resource simultaneously. This can lead to decreased overall program efficiency.

Conclusion
In conclusion, synchronization is an important concept in multi-threaded programming in Java. It provides a mechanism to control access to shared resources, ensuring that only one thread can access a shared resource at a time. This helps prevent data corruption and inconsistent results caused by multiple threads accessing and modifying the same data simultaneously. Java provides the synchronized keyword to implement synchronization, which can be used to mark methods or blocks of code as synchronized. Method-level synchronization and block-level synchronization are the two types of synchronization in Java, with method-level synchronization marking an entire method as synchronized and block-level synchronization marking a portion of a method as synchronized.

FAQs Related to Synchronization in Java

Let us see some Frequently Asked Questions on Synchronization in Java.

Q1: What is the synchronized keyword in Java?
Ans: The synchronized keyword in Java is used to implement synchronization. When a method or a block of code is marked as synchronized, it can only be accessed by one thread at a time. This is achieved by acquiring a lock on the object associated with the synchronized method or block.

Q2: When should I use synchronization in Java?
Ans: You should use synchronization in Java when you need to control access to shared resources in a multi-threaded environment. This helps prevent data corruption and inconsistent results caused by multiple threads accessing and modifying the same data simultaneously.

Q3: What do you mean by Thread?
Ans: A thread in Java is a lightweight, independent unit of execution that runs within a larger program. A thread is capable of executing its own set of instructions, independently of other threads that may be running in the same program.

Leave a Reply

Your email address will not be published. Required fields are marked *