Synchronization in Java is used to control access to shared resources in a multithreaded environment. It ensures that only one thread executes a critical section at a time, preventing data inconsistency.
- Can be applied to methods or specific blocks of code
- Method synchronization locks the entire method
- Block synchronization locks only the critical section
Types of Synchronization
Synchronization in Java can be applied in different ways depending on the level of control required. It helps manage thread access to shared resources efficiently.
1. Method Synchronization
To synchronize a method, add the synchronized keyword. This ensures that only one thread can execute the method at a time.
Example: Unsynchronized Method
class Line {
public void getLine() {
for (int i = 0; i < 3; i++) {
System.out.println(i);
try { Thread.sleep(100); }
catch (Exception e) { System.out.println(e); }
}
}
}
class Train extends Thread {
Line line;
Train(Line line) { this.line = line; }
public void run() { line.getLine(); }
}
public class Geeks {
public static void main(String[] args) {
Line obj = new Line();
Train t1 = new Train(obj);
Train t2 = new Train(obj);
t1.start();
t2.start();
}
}
Output
0 0 1 1 2 2
Explanation: Threads t1 and t2 access the method concurrently, causing mixed output.
Example: Synchronized Method
class Line {
synchronized public void getLine() {
for (int i = 0; i < 3; i++) {
System.out.println(i);
try { Thread.sleep(100); }
catch (Exception e) { System.out.println(e); }
}
}
}
class Train extends Thread {
Line line;
Train(Line line) { this.line = line; }
public void run() { line.getLine(); }
}
public class Geeks {
public static void main(String[] args) {
Line obj = new Line();
Train t1 = new Train(obj);
Train t2 = new Train(obj);
t1.start();
t2.start();
}
}
Output
0 1 2 0 1 2
Explanation: Only one thread executes the method at a time, ensuring data consistency.
2. Block Synchronization
Block synchronization is used when only part of a method contains critical code. This improves performance by allowing threads to execute non-critical code concurrently.
Example: Synchronized Block
import java.util.*;
class Geek {
String name = "";
public int count = 0;
public void geekName(String geek, List<String> list) {
synchronized(this) {
name = geek;
count++;
}
list.add(geek);
}
}
public class GFG {
public static void main(String[] args) {
Geek gk = new Geek();
List<String> list = new ArrayList<>();
gk.geekName("Mohit", list);
System.out.println(gk.name);
}
}
Output
Mohit
Explanation: Only the block updating name and count is synchronized. Adding names to the list runs concurrently.
Method vs Block Synchronization
| Feature | Method Synchronization | Block Synchronization |
|---|---|---|
| Scope | Locks the entire method | Locks only the specific block of code |
| Performance | Can cause unnecessary blocking for non-critical code | More efficient, only critical sections are synchronized |
| Lock | Acquires the lock on the method’s object | Acquires the lock on the object or class specified in the block |
| Flexibility | Less flexible, entire method is locked | More flexible, allows selective synchronization |
Important Points
- A thread entering a synchronized method/block acquires a lock, it releases it upon exit.
- Instance methods/blocks: Acquire object-level lock.
- Static methods/blocks: Acquire class-level lock.
- Synchronization on null objects throws NullPointerException.
- wait(), notify(), and notifyAll() are key methods in synchronization.
- Avoid synchronizing non-final fields to prevent threads from locking different objects.
- synchronized keyword cannot be applied to variables.
Advantages
- Ensures mutual exclusion for shared resources in multithreaded programs.
- Both synchronized instance and static methods can run concurrently because they lock different objects.
Limitations
- Prevents concurrent reads, limiting concurrency.
- Synchronized methods can degrade performance. Prefer block synchronization for critical sections only.