Understanding CLH Locks and Their Enhancement in Java's AbstractQueuedSynchronizer (AQS)
This article explains the fundamentals of spin locks, introduces the CLH lock as an improved spin‑lock variant, analyzes its Java implementation details, and describes how Java's AbstractQueuedSynchronizer refactors CLH locks to provide fair, low‑overhead synchronization for concurrent applications.
In concurrent programming, locks ensure thread safety; Java provides built‑in synchronized locks and various synchronizers in the java.util.concurrent package such as ReentrantLock and CountDownLatch , all built on the AbstractQueuedSynchronizer (AQS) framework.
Spin locks are a simple form of mutual exclusion that repeatedly test a condition until it becomes true. The article presents a basic Java spin‑lock implementation using an AtomicReference<Thread> to acquire and release the lock via a CAS loop.
While spin locks avoid context‑switch overhead, they suffer from starvation and poor performance under high contention because the lock state is centralized, causing frequent cache invalidations.
The CLH lock improves upon spin locks by organizing waiting threads into a queue, guaranteeing FIFO ordering to prevent starvation and decentralizing lock state so each thread spins on its predecessor’s node, reducing cache traffic.
CLH lock data structures consist of a tail pointer and nodes that hold a thread reference and a volatile boolean indicating lock ownership. Threads atomically swap the tail with a new node, then spin on the previous node’s state until it becomes false, at which point they acquire the lock.
The article provides a Java CLH lock implementation and discusses three critical points: (1) why the node’s state variable is declared volatile to enforce a happens‑before relationship; (2) why the lock uses an implicit linked list without explicit predecessor/successor pointers; and (3) the necessity of creating a new node for each lock acquisition to avoid deadlock caused by node reuse.
Advantages of CLH locks include excellent performance, fairness, simplicity, and extensibility, while disadvantages are higher CPU usage for long‑held locks and limited functionality without further extensions.
To address these drawbacks, AQS transforms the CLH lock by replacing spinning with blocking, extending each node with a volatile int waitStatus field (with states such as SIGNAL, PROPAGATE, CONDITION, CANCELLED), explicitly maintaining predecessor and successor links, and nulling references on release to aid garbage collection.
These enhancements enable AQS to support a wide range of synchronizers (e.g., semaphores, barriers) while preserving the core CLH principles of fairness and low overhead.
In summary, the article provides a comprehensive walkthrough from basic spin locks to CLH locks and finally to AQS‑based queue locks, offering code examples, diagrams, and detailed explanations to help readers understand and correctly use Java’s concurrency utilities.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
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.