ReentrantLock.tryLock()未用synchronized,如何实现多线程安全?
Great question—this is such a common point of confusion when digging into Java's concurrency utilities, especially since we’re so conditioned to rely on synchronized for thread safety. Let’s break this down using the code you shared and the under-the-hood mechanics that make it work.
First, let’s address your two core assumptions head-on:
- Assumption 1: If
tryLock()doesn’t usesynchronized, how does it stay thread-safe in multi-threaded environments? - Assumption 2: If it did use
synchronized, why would it be labeled non-blocking?
The short answer: tryLock() relies on atomic operations and volatile state instead of synchronized, letting it avoid blocking while remaining thread-safe. Let’s walk through the code to see exactly how this works.
The tryLock() Entry Point
First, the public tryLock() method simply delegates to the non-fair lock implementation:
public boolean tryLock() { return sync.nonfairTryAcquire(1); }
The Non-Blocking Lock Acquisition Logic
The real logic lives in nonfairTryAcquire(int acquires)—let’s break this code line by line:
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
Key Thread-Safe Mechanisms at Play:
- Volatile State: The
statevariable (retrieved viagetState()) is markedvolatile, which guarantees all threads see the latest value of the lock’s state (0 = unlocked, >0 = locked/reentered). No stale or outdated reads here. - CAS (Compare-And-Swap) Operation: The
compareAndSetState(0, acquires)method is the linchpin. This is an atomic operation supported directly by hardware (via instructions likecmpxchgon x86). It works like this:- Check if the current
stateis still 0 - If yes, atomically set it to
acquires(1 in this case) - If another thread modifies
statebetween the check and set, the operation fails immediately
- Check if the current
Because CAS is atomic, multiple threads can call this at the same time, but only one will succeed in claiming the lock. The rest skip straight to the final return false—no blocking, no waiting around.
Why It’s Non-Blocking:
Unlike synchronized, which parks a thread (puts it into a BLOCKED state) if it can’t acquire the lock, tryLock() takes a "check and exit" approach:
- If the lock is available, grab it and return
true - If the lock is held by another thread, immediately return
false - If the lock is held by the current thread (reentrancy), update the state and return
true
There’s no waiting or suspension involved—each call to tryLock() runs to completion quickly, regardless of what other threads are doing.
Answering Your Original Assumptions
- Assumption 1: It doesn’t need
synchronizedbecause it uses atomic CAS operations and volatile state to enforce thread safety. These primitives are lower-level thansynchronizedand don’t rely on blocking monitor locks. - Assumption 2: It doesn’t use
synchronizedat all—this is exactly why it’s non-blocking. The blocking behavior ofsynchronizedcomes from the JVM’s monitor locking mechanism, whichtryLock()intentionally avoids.
内容的提问来源于stack exchange,提问作者Dibyendu

