Why Does Java Provide Both synchronized and Lock? Uncover the Real Differences
This article explains the core concepts of Java concurrency, comparing mutual exclusion and synchronization, detailing how JUC's Lock and Condition implement monitors, why Lock offers interruptible, timed, and non‑blocking acquisition, and how visibility and reentrancy are guaranteed through volatile state and Happens‑Before rules.
Concurrency programming hinges on two fundamental problems: mutual exclusion (ensuring only one thread accesses a shared resource at a time) and synchronization (coordinating communication and cooperation between threads).
What is the key to concurrent programming?
Java's JUC library solves these problems with the Lock and Condition interfaces, which together form a monitor implementation similar to what synchronized provides.
Although synchronized was the original monitor, it differs from Lock in performance and flexibility. Before JDK 1.5, synchronized was slower; after JDK 1.6 it was optimized, making it comparable. However, Lock can break the non‑preemptive condition that leads to deadlocks, something synchronized cannot do because a thread blocked on a monitor cannot release already‑held resources.
To break the non‑preemptive condition, a lock can be designed with three extra capabilities:
Interruptible acquisition : if a thread holding LockX fails to acquire LockY, it can be interrupted and release LockX.
Timed acquisition : after a timeout the attempt fails, allowing the thread to release any held locks.
Non‑blocking acquisition : the attempt returns immediately with success or failure, again giving the thread a chance to release held locks.
These capabilities correspond to three methods in the Lock interface: lockInterruptibly() – supports interruption
tryLock(long time, TimeUnit unit)– supports timeout
tryLock()– supports non‑blocking acquisition
How does Lock guarantee visibility?
Visibility is ensured by the volatile state field inside the AbstractQueuedSynchronizer (AQS) that backs ReentrantLock. Every lock acquisition reads/writes this volatile variable, and every unlock does the same, establishing a Happens‑Before relationship that propagates memory effects.
The Happens‑Before rules applied are:
Program order: t1.value+=1 Happens‑Before t1.unlock().
Volatile rule: because state becomes 1 after the write, t1.unlock() Happens‑Before t2.lock().
Transitivity: t1.value+=1 Happens‑Before t2.lock().
What is a reentrant lock?
A reentrant lock allows the same thread to acquire the same lock multiple times without deadlocking. The classic usage pattern is:
Lock lock = new ReentrantLock();
lock.lock();
try {
// critical section
lock.lock(); // re‑enter
try {
// nested critical section
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}Reentrancy guarantees thread‑safety even when a thread switches contexts repeatedly.
Explain fair vs. non‑fair locks.
ReentrantLockoffers two constructors: a no‑arg constructor creates a non‑fair lock (default), while the constructor with a boolean fair argument creates a fair lock when true. Fair locks grant the lock to the longest‑waiting thread in the queue; non‑fair locks may allow a newly arriving thread to acquire the lock immediately, bypassing the queue.
Do you know the lock’s entry wait queue?
Each lock maintains a wait queue. Threads that fail to acquire the lock are placed in this queue. When the lock is released, the scheduler wakes the appropriate thread: the longest‑waiting one for a fair lock, or any waiting thread for a non‑fair lock.
Best practices for using locks (Doug Lea’s advice).
Lock only when updating mutable object fields.
Lock only when accessing mutable object fields.
Never lock while calling methods of other objects, as those methods may block, perform I/O, or acquire other locks, leading to deadlocks and performance degradation.
Additional notes: notifyAll() behaves the same for both fair and non‑fair locks; all waiting threads are awakened and re‑enter the entry queue.
CPU‑level atomicity is provided by a single instruction, while Java‑level atomicity is achieved by the monitor (lock) mechanism, which still allows thread scheduling.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
