Synchronization
Synchronization is a modifier that is used for the method and blocks only. If multiple threads are trying to execute simultaneously on the same Java object then there may be chances of data inconsistency problems. To overcome this problem, we should go for a synchronized keyword. If a method or block is 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 inconsistency problem will be resolved.
In synchronization, there are two types of locks on threads:
Object-level lock:
Internally Synchronization concept is implemented by using Locks. Every object in Java has a unique Lock.
Whenever we are using synchronized keyword then only the lock concept will come into picture.
If a thread wants to execute the synchronized method on the given object, first it has to get the lock of that object.
Once the thread got the lock of the object, then it is allowed to execute that any synchronized method on that object.
Once the synchronized method execution completes then the thread automatically releases that lock.
Acquiring and release lock internally is taken care of by JVM and the programmer is not responsible for these activities.
Code:
Output:
Class level lock:
Every class in Java has a unique lock which is nothing but a class level lock.
If a thread wants to execute a static synchronized method, then the thread requires a class level lock.
Once a thread got the class level lock, then it is allowed to execute any static synchronized method of that class.
Once method execution completes automatically thread releases the lock.
Code:
Output:
Synchronized Block:
If very few lines of code requires synchronization then it is not recommended to declare the entire method as synchronized. So we have to enclose those few lines of code by using a synchronized block.
The main advantage of the synchronization block over the synchronized method is it reduces the waiting time of the thread and improves the performance of the system or application.
We can declare Synchronized Block as follows:
1)To get lock of current object:
Code:
public class Main {
public static void main(String[] args) {
Table obj = new Table();//only one object
MyThread1 t1=new MyThread1(obj,5);
t1.setName("First Thread");
MyThread1 t2=new MyThread1(obj,100);
t2.setName("Second Thread");
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
Table t;
int n;
MyThread1(Table t, int n){
this.t=t;
this.n=n;
}
public void run(){
t.printTable(n);
}
}
class Table {
void printTable(int n){
System.out.println(Thread.currentThread().getName()+" Entered into a Method");
synchronized(this){//synchronized block
System.out.println(Thread.currentThread().getName()+" Started");
for(int i=1;i<=5;i++){
System.out.println(n*i);
try{
Thread.sleep(400);
}catch(Exception e){System.out.println(e);}
}
System.out.println(Thread.currentThread().getName()+" Ended");
}
}
}
Output:
Second Thread Entered into a Method
First Thread Entered into a Method
Second Thread Started
100
200
300
400
500
Second Thread Ended
First Thread Started
5
10
15
20
25
First Thread Ended
2)To get lock of particular object:
Code:
public class Main {
public static void main(String[] args) {
Sender sender = new Sender();
SenderWThreads sender1 = new SenderWThreads("Sai ", sender);
SenderWThreads sender2 = new SenderWThreads("Kishore ", sender);
// Start two threads of SenderWThreads type
sender1.start();
sender2.start();
}
}
class Sender {
public void SenderMsg(String msg)
{
System.out.println("\nSending a Message: " + msg);
try
{
Thread.sleep(800);
}
catch (Exception e)
{
System.out.println("Thread interrupted.");
}
System.out.println("\n" +msg+ "Sent");
}
}
// A Sender class for sending a message using Threads
class SenderWThreads extends Thread {
private String msg;
Sender sd;
// Receiver method to receive a message object and a message to be sent
SenderWThreads(String m, Sender obj)
{
msg = m;
sd = obj;
}
public void run()
{
// Checks that only one thread sends a message at a time.
synchronized(sd)
{
// synchronizing the sender object
sd.SenderMsg(msg);
}
}
}
Output:
Sending a Message: Sai
Sai Sent
Sending a Message: Kishore
Kishore Sent
Advantages of synchronized
in Java
Thread Safety: Prevents race conditions and ensures data consistency by allowing only one thread to access critical sections at a time.
Simplicity: Easy to implement and provides a built-in mechanism for concurrency control.
Predictable Execution: Ensures orderly access to shared resources, simplifying debugging and reasoning about the program.
Disadvantages of synchronized
in Java
Performance Overhead: Causes threads to block, leading to potential performance bottlenecks.
Limited Scalability: Can reduce the overall efficiency of multithreaded applications due to increased waiting times.
Deadlocks: Risk of deadlocks if not used carefully, which can halt the program's execution.