首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

JUC 锁源码深度解析:ReentrantLock 与 ReentrantReadWriteLock 实现原理

     編輯:Java 綜合教學

类体系概览

Lock (接口)
  └── ReentrantLock (可重入独占锁)
        └── Sync extends AbstractQueuedSynchronizer (AQS)
              ├── NonfairSync (非公平,默认)
              └── FairSync (公平)

ReadWriteLock (接口)
  └── ReentrantReadWriteLock (可重入读写锁)
        ├── ReadLock (共享锁)
        ├── WriteLock (独占锁)
        └── Sync extends AQS
              ├── NonfairSync
              └── FairSync

一、ReentrantLock 源码核心

1. 两把锁的获取入口

  • 非公平锁:lock() → 先 CAS 抢占 compareAndSetState(0,1) 成功即得,失败走 acquire(1) 入队。
  • 公平锁:lock() → 直接 acquire(1),tryAcquire 中检查 !hasQueuedPredecessors() 确保队头优先。

2. 核心模板方法实现

// 非公平尝试获取(非公平锁 lock()、tryLock() 直接调用)
final boolean nonfairTryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) { // 无锁
        if (compareAndSetState(0, acquires)) { // CAS 抢占
            setExclusiveOwnerThread(current);
            return true;
        }
    } else if (current == getExclusiveOwnerThread()) { // 重入
        int nextc = c + acquires;
        if (nextc < 0) throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

// 释放
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) { // 完全释放
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free; // 返回 true 则 unparkSuccessor 唤醒后继
}

// 公平锁尝试获取
protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // 关键差异:检查队列前驱
        if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    } else if (current == getExclusiveOwnerThread()) {
        // 重入逻辑同非公平
    }
    return false;
}

3. 监控方法

  • getHoldCount():当前线程重入次数。
  • isHeldByCurrentThread():是否持有锁。
  • isLocked():锁是否被占用。
  • getQueueLength()、hasQueuedThreads()、getQueuedThreads():队列状态。
  • newCondition():创建 ConditionObject。

二、ReentrantReadWriteLock 源码核心

1. 状态压缩设计

一个 int state 存双值:

  • 高 16 位:sharedCount(读锁持有数)。
  • 低 16 位:exclusiveCount(写锁重入数)。
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = 1 << SHARED_SHIFT; // 0x00010000
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; // 0xFFFF
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

2. 写锁(独占)获取

protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    int w = exclusiveCount(c);
    if (c != 0) { // 有锁存在
        if (w == 0 || current != getExclusiveOwnerThread()) return false; // 有读锁或别的写锁
        if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded");
        setState(c + acquires); // 重入
        return true;
    }
    // 无锁:公平性检查 + CAS
    if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) return false;
    setExclusiveOwnerThread(current);
    return true;
}

3. 读锁(共享)获取

protected final int tryAcquireShared(int unused) {
    Thread current = Thread.currentThread();
    int c = getState();
    // 有写锁且非当前线程 -> 失败
    if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1;
    int r = sharedCount(c);
    // 公平性检查 + 未达上限 + CAS
    if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {
        // 记录当前线程读锁计数(ThreadLocal + 首读者优化)
        if (r == 0) { firstReader = current; firstReaderHoldCount = 1; }
        else if (firstReader == current) { firstReaderHoldCount++; }
        else { /* ThreadLocalHoldCounter 计数 */ }
        return 1; // 成功
    }
    return fullTryAcquireShared(current); // 复杂情况循环尝试
}

4. 公平与非公平策略

// 非公平:writerShouldBlock=false, readerShouldBlock=false (或检查队头是否写锁)
static final class NonfairSync extends Sync {
    final boolean writerShouldBlock() { return false; }
    final boolean readerShouldBlock() { return false; /* 或 apparentlyFirstQueuedIsExclusive() */ }
}

// 公平:writerShouldBlock/readerShouldBlock 均为 hasQueuedPredecessors()
static final class FairSync extends Sync {
    final boolean writerShouldBlock() { return hasQueuedPredecessors(); }
    final boolean readerShouldBlock() { return hasQueuedPredecessors(); }
}

5. 读锁释放与计数器管理

使用 ThreadLocalHoldCounter 维护每线程读锁计数,释放时递减,CAS 递减 state 高 16 位。

三、关键设计亮点总结

  1. AQS 模板方法:将同步语义(tryAcquire/Release)下沉子类,队列管理、阻塞唤醒上收父类。
  2. 状态压缩:ReadWriteLock 用 32 位 int 存双计数,位运算极致高效。
  3. 首读者优化:避免 ThreadLocal 开销,首个读线程计数存实例字段。
  4. 公平性可插拔:通过 writerShouldBlock/readerShouldBlock 策略方法控制插队行为。
  5. 重入支持:独占锁靠 exclusiveOwnerThread,共享锁靠 ThreadLocalHoldCounter。

适用场景建议

  • ReentrantLock:替代 synchronized,需可中断、超时、公平、多 Condition 场景。
  • ReentrantReadWriteLock:读多写少、读操作耗时较长(如缓存、配置加载),读读并发、读写互斥、写写互斥。
  • StampedLock (JDK8+):更高性能读写锁,支持乐观读,但不可重入,慎用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved