Backend Development 28 min read

Comprehensive Guide to Java Locks: Synchronized, ReentrantLock, AQS, and Distributed Locks

This article provides an in‑depth overview of Java locking mechanisms, covering lock classifications, the inner workings of the synchronized keyword, ReentrantLock, AbstractQueuedSynchronizer, various lock optimizations, and practical implementations of distributed locks using Redis and Zookeeper.

政采云技术
政采云技术
政采云技术
Comprehensive Guide to Java Locks: Synchronized, ReentrantLock, AQS, and Distributed Locks

Preface

Locks are an unavoidable topic in programming. This article thoroughly analyzes Java's synchronized keyword, the lock wrapper class ReentrantLock , the AbstractQueuedSynchronizer (AQS), and distributed locks, explaining their principles, source code, and usage scenarios.

Lock Classification

Optimistic lock – low contention, short execution time.

Pessimistic lock – high contention, long execution time.

Fair lock – threads acquire the lock in arrival order.

Unfair lock – threads acquire the lock randomly.

Exclusive lock – held by a single thread.

Shared lock – held by multiple threads.

Reentrant lock – the owning thread can reacquire the lock.

Spin lock – retries a limited number of times without yielding the CPU, suitable for low‑contention scenarios.

Synchronized

The JVM built‑in synchronization tool, originally inefficient but heavily optimized in later JDK versions.

Lock Objects

Class or static methods – lock the class object.

Instance methods or this – lock the instance object.

Implementation Principle

Synchronized is implemented using the bytecode instructions monitorenter and monitorexit .

monitorenter acquires the monitor, increments the lock counter, and blocks other threads if the counter is already non‑zero.

monitorexit releases the monitor, decrements the counter, and fully releases the lock when the counter reaches zero.

Lock Optimizations

Lock coarsening – merges adjacent lock regions into a larger lock.

Lock elimination – removes unnecessary locks via JIT escape analysis.

Biased locking – avoids lock acquisition overhead when a lock is used by a single thread without contention.

Lightweight locking – uses CAS on the object’s Mark Word to acquire a lock without OS mutexes.

Spin (busy‑waiting) – repeatedly attempts to acquire a lock while keeping the CPU busy.

Adaptive spinning – adjusts spin duration based on previous acquisition success.

Heavyweight lock – falls back to OS mutex when contention is high.

Structure of a Synchronized Object

The object header consists of the Mark Word (hash code, GC age, lock bits, biased‑lock flag) and, for arrays, a class pointer and length field.

Lock Upgrade Process

Object is ordinary – Mark Word stores hash code, lock flag = 01, biased flag = 0.

Thread A acquires a biased lock – lock flag stays 01, biased flag becomes 1, Mark Word records A’s thread ID.

Thread A re‑enters – sees its own ID and continues without further synchronization.

Thread B attempts – CAS tries to acquire; if it fails, the lock upgrades to lightweight.

Lightweight lock fails – thread spins.

Spin fails – lock upgrades to heavyweight, blocking other threads.

java.util.concurrent.locks Core Classes

LockSupport provides low‑level lock primitives implemented by the Unsafe class via native methods:

public native void unpark(Object var1);
public native void park(boolean var1, long var2);

ReentrantLock’s logic is delegated to its internal Sync class:

public void lock() { sync.lock(); }
// Fair lock
final void lock() { acquire(1); }
// Non‑fair lock
final void lock() { if (compareAndSetState(0,1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }

ReadWriteLock solves the multiple‑reader‑single‑writer problem, while StampedLock introduces an optimistic read mode that allows concurrent writes at the cost of validation.

Key Elements of a Lock Implementation

A state variable (0 = unlocked, 1 = locked, >1 = re‑entrant).

Reference to the owning thread.

Support for blocking and unparking threads (via LockSupport ).

A queue (CLH queue) that holds waiting threads, implemented with CAS.

AQS Core

AQS uses a volatile int state and a FIFO CLH queue to manage exclusive and shared acquisition, providing methods such as tryAcquire , tryRelease , tryAcquireShared , and tryReleaseShared .

private volatile int state;
protected final boolean compareAndSetState(int expect, int update) { return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }

Exclusive mode is used by locks like ReentrantLock ; shared mode is used by constructs such as Semaphore , CountDownLatch , and ReadWriteLock .

ReentrantLock Details

Internal structure includes a reference to AbstractQueuedSynchronizer .

Default is a non‑fair lock.

Lock acquisition uses CAS on state and sets the exclusive owner thread.

Re‑entrance increments state ; unlocking decrements it and wakes the next waiting thread.

Fair lock checks the queue before attempting acquisition.

Timeout acquisition uses tryAcquireNanos with park timeout.

ReentrantReadWriteLock

Write lock acquisition checks exclusive count and uses CAS; read lock acquisition increments the shared count. Lock downgrade (write → read) is necessary for visibility guarantees.

protected final boolean tryAcquire(int acquires) { /* write lock logic */ }

Distributed Locks

Distributed locks coordinate across multiple JVMs. Common implementations use Redis or Zookeeper.

Redis example (Jedis API):

jedisClientUtil.set(lockKey.toString(), CLIENT_ID + Thread.currentThread().getId(),
        JedisClientUtil.SetPremise.NX, JedisClientUtil.ExpireType.Milliseconds, unit.toMillis(expiration));
private static final String DELETE_SCRIPT =
  "if redis.call('get',KEYS[1]) == ARGV[1] then\n" +
  "  return redis.call('del',KEYS[1])\n" +
  "else\n" +
  "  return 0\n" +
  "end";

Key considerations: always set an expiration, release the lock on completion or error, and decide whether other threads may release the lock.

Redisson provides an auto‑renewal mechanism based on a time‑wheel scheduler.

Conclusion

The article walks through lock fundamentals from the basic synchronized keyword to JDK concurrency utilities and finally to distributed lock solutions, offering a complete reference for developers dealing with concurrency in Java.

JavaconcurrencyLocksAQSReentrantLocksynchronizedDistributedLock
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

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.