In this article Synchronization in Java we give the information about Synchronization in Java is a mechanism that allows only one thread to access a shared resource (such as an object, variable, or file) at a time.
Synchronization in Java
Introduction
In Java, synchronization is a mechanism that ensures that only one thread can access a shared resource—such as an object, variable, or file—at any given time.
It plays a crucial role in multithreading, preventing multiple threads from modifying shared data simultaneously and thereby maintaining data integrity and consistency.
Why is Synchronization Necessary?
When two or more threads operate concurrently on the same object or variable, it can lead to race conditions or data inconsistency.
Synchronization helps eliminate these issues by allowing only one thread to execute a critical section of code at a time. This ensures thread safety and reliable program execution.
Types of Synchronization in Java
Java provides several mechanisms to implement synchronization:
-
Synchronized Method
A synchronized method ensures that only one thread can access it for a particular object instance at a time.
The keyword synchronized is used to define such methods.
Example:
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); }
}
public class TestSynchronization {
public static void main(String args[]) {
Table obj = new Table();
MyThread1 t1 = new MyThread1(obj);
MyThread2 t2 = new MyThread2(obj);
t1.start();
t2.start();
}
}
Output Behavior:
Only one thread executes the synchronized method at a time. Thus, the output of one thread completes before the other starts, preventing interleaved results.
-
Synchronized Block
A synchronized block is used when synchronization is required only for a specific portion of a method rather than the entire method.
It provides better performance since the non-critical parts of the method can still be executed by multiple threads concurrently.
Syntax:
synchronized(object) {
// synchronized code
}
Example: Odd–Even Program Using a Synchronized Block
class Printer {
void printNumbers(String type) {
synchronized (this) {
if (type.equals(“even”)) {
System.out.println(“Even numbers:”);
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
System.out.println(i);
try { Thread.sleep(300); } catch (Exception e) {}
}
}
} else {
System.out.println(“Odd numbers:”);
for (int i = 1; i <= 10; i++) {
if (i % 2 != 0) {
System.out.println(i);
try { Thread.sleep(300); } catch (Exception e) {}
}
}
}
}
}
}
class OddThread extends Thread {
Printer p;
OddThread(Printer p) { this.p = p; }
public void run() { p.printNumbers(“odd”); }
}
class EvenThread extends Thread {
Printer p;
EvenThread(Printer p) { this.p = p; }
public void run() { p.printNumbers(“even”); }
}
public class SyncOddEven {
public static void main(String[] args) {
Printer p = new Printer();
OddThread t1 = new OddThread(p);
EvenThread t2 = new EvenThread(p);
t1.start();
t2.start();
}
}
Output Behavior:
Since both threads share the same Printer object, the synchronized block ensures that one thread completes its printing before the other begins, avoiding mixed output.
-
Static Synchronization
When a static synchronized method is declared, the lock is applied at the class level, not on a specific object.
This means that only one thread can access any static synchronized method of the class at a time, regardless of how many objects of the class exist.
Example: Static Synchronization (Area Calculation)
class AreaCalculator {
synchronized static void calculateArea(int length, int width) {
System.out.println(“Calculating area for: ” + length + ” x ” + width);
int area = length * width;
try {
Thread.sleep(500);
} catch (Exception e) {
System.out.println(e);
}
System.out.println(“Area = ” + area);
System.out.println(“————————–“);
}
}
class MyThread1 extends Thread {
public void run() { AreaCalculator.calculateArea(5, 3); }
}
class MyThread2 extends Thread {
public void run() { AreaCalculator.calculateArea(7, 4); }
}
class MyThread3 extends Thread {
public void run() { AreaCalculator.calculateArea(10, 2); }
}
public class StaticSyncArea {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
MyThread3 t3 = new MyThread3();
t1.start();
t2.start();
t3.start();
}
}
Output Behavior:
Even though multiple threads are started, only one can execute the calculateArea() method at a time, as the lock is on the class itself.
The Concept of Locks
Each object in Java has an intrinsic monitor lock (also known as an object lock).
When a thread enters a synchronized method or block, it acquires that lock.
Other threads attempting to access the same synchronized section must wait until the lock is released.
Key Points
- Synchronization ensures data consistency in multithreaded environments.
- It may reduce performance due to the overhead of acquiring and releasing locks.
- It should be applied only when threads share resources.
- Poor synchronization design can lead to deadlocks, where two or more threads wait indefinitely for each other’s locks.
Conclusion
Synchronization in Java is an essential mechanism to maintain thread safety and data consistency in multithreaded applications.
By ensuring that only one thread can execute critical code sections at a time, synchronization effectively prevents race conditions and ensures the reliable and predictable behavior of concurrent programs.
Some More:
POP- Introduction to Programming Using ‘C’
OOP – Object Oriented Programming
DBMS – Database Management System
RDBMS – Relational Database Management System