Backend Development 24 min read

Understanding JVM-Level Locks in Java: synchronized, ReentrantLock, ReentrantReadWriteLock, and LongAdder

This article explains the evolution and implementation of Java's JVM‑level locks—including synchronized, ReentrantLock, ReentrantReadWriteLock, and LongAdder—detailing their lock‑upgrade process, internal object layout, AQS‑based algorithms, and how they improve concurrency and performance in multithreaded applications.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding JVM-Level Locks in Java: synchronized, ReentrantLock, ReentrantReadWriteLock, and LongAdder

Modern multi‑core CPUs have made multithreaded programming essential, but it introduces data‑race problems that are solved by various locking mechanisms in the Java Virtual Machine. The article first introduces the classic synchronized keyword, describing how its implementation evolved from a heavyweight lock to a lightweight one after JDK 1.5, and explains the object header layout (MarkWord, Class Pointer, instance data, and padding) that stores lock state.

The lock‑upgrade sequence—biased lock → lightweight lock → heavyweight lock—is illustrated with diagrams and explained: a thread acquires a biased lock when no contention exists; contention triggers upgrade to a lightweight lock using CAS on the MarkWord; heavy contention or long spin counts cause escalation to a heavyweight lock that involves the operating system.

ReentrantLock is built on the AbstractQueuedSynchronizer (AQS) framework. It provides explicit lock() and unlock() methods, supports reentrancy via a volatile state counter, allows timeout with tryLock() , can be configured as fair or non‑fair, and offers an interruptible lock acquisition via lockInterruptibly() . Example code shows how the lock is acquired and released:

public void lock() { sync.acquire(1); }
protected final boolean tryAcquire(int acquires) { ... }

ReentrantReadWriteLock consists of a write lock (exclusive, pessimistic) and a read lock (shared, optimistic). It also relies on AQS, splitting the 32‑bit state into high 16 bits for write‑lock count and low 16 bits for read‑lock count. The article details the acquisition and release algorithms for both locks, including handling of first reader optimization and thread‑local counters.

public void lock() { sync.acquireShared(1); }
protected final int tryAcquireShared(int unused) { ... }

The LongAdder class, introduced in JDK 1.8, addresses contention on atomic counters by using a striped approach: a base variable is updated via CAS, and when contention rises, an array of Cell objects is created, each updated by a different thread. This reduces hot‑spot contention compared to AtomicInteger and is similar to the technique used in ConcurrentHashMap .

Overall, the article provides a comprehensive overview of JVM‑level locking primitives, their internal mechanisms, and practical considerations for choosing the appropriate lock in high‑concurrency Java applications.

JavaconcurrencyLongAdderLocksReentrantLocksynchronizedreadwritelock
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

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