Unlocking Java’s Synchronized: How the JVM Implements Locks
This article explains the low‑level implementation of Java's synchronized keyword, covering monitorenter/monitorexit bytecode, object header structures, Mark Word layouts, and the evolution from heavyweight locks to biased and lightweight locks with lock‑upgrade mechanisms.
When beginners start learning Java concurrency, they immediately encounter the synchronized keyword. Before JDK 1.5 it behaved as a heavyweight lock with poor performance. JDK 1.6 introduced optimizations such as biased locking and lightweight locking, greatly improving lock acquisition and release efficiency.
Underlying Implementation of Synchronized
Synchronization Principle
First, decompile the following method1:
public void method1() {
synchronized (this) {
System.out.println("This is the synchronized");
}
}The decompiled bytecode shows that the synchronized block is implemented with the monitorenter and monitorexit instructions.
During execution, monitorenter is inserted at the start of the synchronized block and monitorexit at the end (or on exception). The JVM guarantees that each monitorenter has a matching monitorexit. Every object has an associated monitor; when a thread reaches monitorenter, it attempts to acquire the monitor’s ownership.
Synchronized Method Synchronization
Consider a synchronized method:
public synchronized void method2() {
System.out.println("This is the synchronized method");
}A synchronized method does not have a dedicated bytecode instruction. Instead, the JVM checks the method’s ACC_SYNCHRONIZED flag; if set, the thread acquires the monitor before execution and releases it after the method returns.
Java Object Header
The lock used by synchronized resides in the Java object header. Arrays use a three‑word header; non‑array objects use a two‑word header. In a 32‑bit JVM, one word equals 4 bytes.
The header consists of the Mark Word and the Class Pointer. The Mark Word stores runtime data such as hash code, generation age, and lock flags, and is crucial for implementing lightweight and biased locks.
During execution, the Mark Word changes according to the lock state. It can represent four different states: unlocked, biased lock, lightweight lock, and heavyweight lock.
In a 64‑bit JVM the Mark Word is 64 bits; its layout is analogous but with larger fields.
Lock Upgrade
Synchronized contains a hidden lock‑upgrade process that enables high performance. The lock can transition from no‑lock → biased → lightweight → heavyweight, upgrading as contention increases. Upgrades are one‑way; a lock never downgrades.
Biased Lock
When a thread repeatedly acquires a lock without contention, the JVM stores the thread ID in the object’s Mark Word, creating a biased lock. Subsequent entries by the same thread only need to verify the Mark Word, avoiding CAS operations.
If the verification fails, the JVM checks whether the biased‑lock flag is set. If not, it falls back to a CAS‑based lock acquisition; otherwise it attempts to re‑bias the lock to the current thread.
Biased locking is enabled by default in Java 6 and 7 but activates a few seconds after startup. It can be disabled with the JVM option -XX:-UseBiasedLocking or by setting the startup delay to zero.
-XX:-UseBiasedLocking=falseLightweight Lock
Lightweight locking is used when there is no contention. The JVM creates a lock record on the thread’s stack, copies the object’s Mark Word into it (the displaced Mark Word), and attempts a CAS to replace the Mark Word with a pointer to the lock record. If successful, the thread holds the lock; otherwise it spins or inflates to a heavyweight lock.
Unlocking restores the original Mark Word via CAS. If another thread has already caused inflation, the lock becomes heavyweight and will not revert to lightweight.
Lock Pros and Cons Comparison
The following table summarizes the advantages, disadvantages, and typical use cases of biased, lightweight, and heavyweight locks.
Summary
We explored the low‑level mechanics of Java’s synchronized keyword, from monitor bytecode instructions to object‑header structures and Mark Word state transitions. We examined how biased locking and lightweight locking are introduced to reduce contention, and how the JVM transparently upgrades locks to heavyweight when necessary. Understanding these details helps developers appreciate why synchronized can be both simple to use and highly performant in modern JDKs.
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.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
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.
