Understanding Java Locks: From Synchronized to Lock Upgrade Mechanisms
This article explains how Java implements locks—from the basic use of the synchronized keyword and Lock interface to the internal object header structures, bias, lightweight, and heavyweight lock upgrades, and the role of CAS and monitor objects in JVM concurrency control.
As business scales and user traffic grows, high‑concurrency becomes a challenging problem for developers, and mastering Java's concurrency mechanisms is essential for writing correct and efficient multithreaded programs.
Java provides two main categories of synchronization primitives: the JVM‑level synchronized keyword and the Java‑API level Lock interface implementations such as ReentrantLock and ReentrantReadWriteLock. The article first presents a simple example illustrating the three ways synchronized can be applied.
public class LockTest {
Object obj = new Object();
public static synchronized void testMethod1() {
// synchronized code
}
public synchronized void testMethod2() {
// synchronized code
}
public void testMethod3() {
synchronized (obj) {
// synchronized code
}
}
}The lock used by synchronized always depends on a specific object: a static method locks the class object, an instance method locks this, and a synchronized block locks the object referenced in the parentheses.
Every Java object consists of an object header, instance data, and alignment padding. The header contains a Mark Word that stores hash code, garbage‑collection age, and lock information. The article shows how the Mark Word evolves during lock acquisition.
Since JDK 1.6, the HotSpot VM optimizes synchronized with a lock‑upgrade process: no‑lock → bias lock → lightweight lock → heavyweight lock . Bias lock records the owning thread ID directly in the Mark Word, allowing fast re‑entry when the same thread repeatedly acquires the lock.
When contention appears, the bias lock is revoked and the lock upgrades to a lightweight lock. The VM creates a Lock Record on the owning thread’s stack, copies the Mark Word into it, and uses CAS to replace the Mark Word with a pointer to this record.
If contention becomes severe, the lightweight lock further upgrades to a heavyweight (monitor) lock. The heavyweight lock is represented by an ObjectMonitor structure implemented in C++. A simplified definition is shown below:
ObjectMonitor() {
_header = NULL;
_count = 0; // lock acquisition count
_waiters = 0,
_recursions = 0; // re‑entry count
_object = NULL;
_owner = NULL; // thread that owns the monitor
_WaitSet = NULL; // threads waiting on wait()
_WaitSetLock = 0;
_Responsible = NULL;
_succ = NULL;
_cxq = NULL;
FreeNext = NULL;
_EntryList = NULL; // threads blocked trying to acquire the lock
_SpinFreq = 0;
_SpinClock = 0;
OwnerIsThread = 0;
}The heavyweight lock uses the monitor to block contending threads and to support wait / notify semantics, avoiding wasteful CPU spinning.
Finally, the article notes that modern high‑performance systems often prefer optimistic concurrency control such as CAS, which is also employed internally during the lock‑upgrade steps, illustrating the close relationship between traditional synchronized and lock‑free techniques.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.
