You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReentrantLock.tryLock()未用synchronized,如何实现多线程安全?

How does ReentrantLock's tryLock() work without blocking or 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 use synchronized, 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:

  1. Volatile State: The state variable (retrieved via getState()) is marked volatile, which guarantees all threads see the latest value of the lock’s state (0 = unlocked, >0 = locked/reentered). No stale or outdated reads here.
  2. CAS (Compare-And-Swap) Operation: The compareAndSetState(0, acquires) method is the linchpin. This is an atomic operation supported directly by hardware (via instructions like cmpxchg on x86). It works like this:
    • Check if the current state is still 0
    • If yes, atomically set it to acquires (1 in this case)
    • If another thread modifies state between the check and set, the operation fails immediately

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 synchronized because it uses atomic CAS operations and volatile state to enforce thread safety. These primitives are lower-level than synchronized and don’t rely on blocking monitor locks.
  • Assumption 2: It doesn’t use synchronized at all—this is exactly why it’s non-blocking. The blocking behavior of synchronized comes from the JVM’s monitor locking mechanism, which tryLock() intentionally avoids.

内容的提问来源于stack exchange,提问作者Dibyendu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:14:51