Understanding the Implementation of synchronized in Java and Its Differences with Lock
This article explains how Java's synchronized keyword works at the JVM level, detailing monitorenter/monitorexit bytecode, the role of object monitors, differences between synchronized methods and blocks, and compares its behavior and performance with explicit Lock implementations such as ReentrantLock, including code examples and practical considerations.
Java allows any object to be used as a lock, and the synchronized keyword provides the basic mechanism for synchronized execution. The lock for a normal synchronized method is the current instance, for a static synchronized method it is the Class object, and for a synchronized block it is the object specified in the parentheses.
When a thread enters a synchronized block, it must acquire the lock; upon exiting or throwing an exception it must release the lock. The article shows a simple example:
package cn.alibab.javap;
public class SynchronizedTest {
public synchronized void test1() {
}
public void test2() {
synchronized (this) {
}
}
}Using javap to inspect the generated class file reveals that synchronized blocks are implemented with the bytecode instructions monitorenter and monitorexit . Synchronized methods do not have special bytecode; instead the JVM sets the ACC_SYNCHRONIZED flag in the method's access flags, indicating that the method should be executed with the monitor of the owning object or class.
The article then compares synchronized code blocks and synchronized methods, explaining that both rely on the monitorenter/monitorexit pair, and that every monitor must have a matching monitorexit to ensure proper release.
synchronized vs. Lock
synchronized is a language keyword whose lock management is handled by the JVM. It is simpler to use and, under low contention, can perform better. Lock (e.g., ReentrantLock ) is an interface‑based API that offers more flexibility: explicit lock/unlock, tryLock, interruptible lock acquisition, and condition variables for advanced thread coordination.
Exceptions automatically release the lock in synchronized , preventing deadlocks; with Lock you must manually unlock, typically in a finally block.
Lock supports interruptible lock acquisition and tryLock to check lock availability, which synchronized lacks.
Read‑write separation can be achieved with ReadWriteLock , improving read‑heavy scenarios.
Under high contention, Lock often outperforms synchronized because it uses optimistic locking (CAS) and non‑blocking algorithms.
Performance-wise, early Java versions (1.5) treated synchronized as a heavyweight operation, but from Java 1.6 onward many optimizations (biased locking, lightweight locking, lock elision, lock coarsening) made its performance comparable to Lock . The JVM now prefers synchronized for most cases, while Lock remains useful for complex synchronization requirements.
The article also shows how ReentrantLock internally uses compareAndSetState (a CAS operation) to acquire the lock, illustrating the optimistic locking mechanism.
In summary, synchronized offers simplicity and automatic lock release, suitable for low‑to‑moderate contention, whereas Lock provides richer features and better performance under heavy contention, at the cost of explicit management.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.