How do I use ReentrantLock vs synchronized?
In Java, both synchronized and ReentrantLock are used to manage thread safety, but they offer different levels of control and flexibility. 1. synchronized Keyword The synchronized keyword is the built-in mechanism in Java for mutual exclusion. It is simpler to use because the JVM automatically handles acquiring and releasing the lock. Usage: Can be applied […]
Artikel oleh Wayan · Sumber: Kode Java ↗
Terjemahan artikel ini belum tersedia. Isi asli ditampilkan.
In Java, both synchronized and ReentrantLock are used to manage thread safety, but they offer different levels of control and flexibility.
1. synchronized Keyword
The synchronized keyword is the built-in mechanism in Java for mutual exclusion. It is simpler to use because the JVM automatically handles acquiring and releasing the lock.
- Usage: Can be applied to methods or used as a block.
- Automatic Release: The lock is automatically released when the thread exits the block or method, even if an exception occurs.
- Performance: In modern JVMs,
synchronizedis highly optimized (biased locking, lightweight locking) and often performs just as well asReentrantLock.
Example:
package org.kodejava.util.concurrent;
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public void incrementBlock() {
synchronized (this) {
count++;
}
}
}
2. ReentrantLock Class
ReentrantLock (from java.util.concurrent.locks) is an explicit lock implementation that provides advanced features not available with synchronized.
- Manual Control: You must explicitly call
lock()andunlock(). It is critical to use atry-finallyblock to ensure the lock is released. - Fairness: You can create a “fair” lock that gives preference to the longest-waiting thread.
- Try Lock:
tryLock()allows a thread to attempt to acquire the lock without blocking indefinitely. - Interruptible: A thread waiting for a
ReentrantLockcan be interrupted vialockInterruptibly().
Example:
package org.kodejava.util.concurrent;
import java.util.concurrent.locks.ReentrantLock;
public class LockCounter {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
// Always unlock in finally to prevent deadlocks
lock.unlock();
}
}
}
Key Differences
| Feature | synchronized |
ReentrantLock |
|---|---|---|
| Ease of Use | Very easy; handled by JVM. | Requires manual try-finally. |
| Fairness | Not supported. | Supported (optional constructor parameter). |
| Flexibility | Rigid block structure. | Highly flexible (can lock in one method, unlock in another). |
| Non-blocking | No (thread always waits). | Yes, via tryLock(). |
| Interruptibility | No. | Yes, via lockInterruptibly(). |
Which should you choose?
- Use
synchronizedby default. It’s cleaner, less error-prone, and sufficient for most basic thread-safety needs. - Use
ReentrantLockwhen you need advanced features like:- Timing out while waiting for a lock (
tryLock(timeout)). - Allowing the lock attempt to be interrupted.
- Using a “Fair” lock strategy.
- Complex locking structures that aren’t strictly nested.
- Timing out while waiting for a lock (
If you are debugging concurrency issues, IntelliJ IDEA provides tools to inspect thread states and detect blocked monitors [1]. You can also use the Threads tab in the Debugger to see which thread owns a monitor or is waiting for one [2].
