Java Lock Framework vs Thread Synchronization
Last Updated :
24 Oct, 2025
In multi-threaded Java programs, thread synchronization ensures that only one thread accesses a shared resource at a time, preventing race conditions, data corruption, or inconsistency. This can be achieved using either the synchronized keyword or the Lock framework (java.util.concurrent).
Thread Synchronization
Thread synchronization is the simplest mechanism to control access to shared resources. Using the synchronized keyword, a thread can acquire a lock on an object or method, ensuring that only one thread executes the critical section at a time.
Java
class Counter{
private int c = 0;
// Synchronized method ensures only one thread at a time
public synchronized void increment(){
c++;
}
public int getCount(){
return c;
}
}
public class GFG{
public static void main(String[] args)
throws InterruptedException{
Counter counter = new Counter();
Runnable task = () ->
{
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count (synchronized): "
+ counter.getCount());
}
}
OutputFinal Count (synchronized): 2000
Explanation:
- increment() is synchronized, so only one thread can execute it at a time.
- t1.join() and t2.join() ensure the main thread waits for both threads to finish.
- Without synchronized, the final count might be less than 2000 due to race conditions.
Lock Framework
The Lock framework, based on the Lock interface, provides explicit control over thread access. ReentrantLock is its most common implementation, offering features like manual locking/unlocking and non-blocking attempts with tryLock(), unlike synchronized blocks.
Java
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class LockCounter{
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment()
{
lock.lock();
try {
count++;
}
finally {
lock.unlock(); // Always release lock
}
}
public int getCount(){
return count;
}
}
public class Geeks{
public static void main(String[] args)
throws InterruptedException{
LockCounter counter = new LockCounter();
Runnable task = () ->
{
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count (ReentrantLock): "
+ counter.getCount());
}
}
OutputFinal Count (ReentrantLock): 2000
Explanation:
- lock.lock() manually acquires the lock before modifying the counter.
- The try-finally block ensures the lock is always released, even if an error occurs.
- This allows more control, such as checking lock availability (tryLock) or waiting with timeout.
- The program safely increments the counter to 2000, similar to synchronized.
Which One to Use?
Use synchronized when:
- The critical section is small and simple.
- Low contention between threads is expected.
- We want simpler, less verbose code.
Use Lock framework when
- You need high concurrency or advanced control over threads.
- The program requires timed or interruptible locks.
- There are read-heavy operations that can benefit from ReentrantReadWriteLock.
- We want to implement fairness policies or need to avoid deadlocks explicitly.
Rule of Thumb: For simple scenarios, synchronized is enough. For scalable, complex multi-threading, prefer Lock framework.
Lock Framework vs Thread Synchronization
| Features | Lock Framework | Thread Synchronization (synchronized) |
|---|
| Flexibility | More flexible. Allows multiple locks for different methods. | Limited flexibility. Only one lock can be applied per method or class. |
|---|
| Concurrency | Allows higher concurrency by using different locks for different tasks. | Less concurrency due to locking the entire method or class. |
|---|
| Control Over Locking | Provides explicit control over when to lock and unlock. | Implicit locking with no control over the exact limit. |
|---|
| List of waiting threads | The list of waiting threads can be seen using the Lock framework | Not possible with synchronized. |
|---|
| Deadlock Prevention | Offers better strategies to avoid deadlocks using try-lock mechanisms. |
Less control over deadlock prevention.
|
|---|
Interruptible | Supports interruptible lock acquisition (e.g., lock.tryLock()) | Synchronized blocks are non-interruptible. |
|---|
Explore
Java Basics
OOP & Interfaces
Collections
Exception Handling
Java Advanced
Practice Java