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.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Unlocking Java’s Synchronized: How the JVM Implements Locks

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.

Decompiled method1 bytecode
Decompiled method1 bytecode

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");
}
Synchronized method bytecode
Synchronized method bytecode

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.

Object header layout
Object header layout

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.

Mark Word structure (32‑bit)
Mark Word structure (32‑bit)

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.

Mark Word state transitions
Mark Word state transitions

In a 64‑bit JVM the Mark Word is 64 bits; its layout is analogous but with larger fields.

Mark Word layout (64‑bit)
Mark Word layout (64‑bit)

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=false

Lightweight 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.

Lightweight lock inflation
Lightweight lock inflation

Lock Pros and Cons Comparison

The following table summarizes the advantages, disadvantages, and typical use cases of biased, lightweight, and heavyweight locks.

Lock comparison table
Lock comparison table

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJVMconcurrencyLocksynchronized
Su San Talks Tech
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.