当前位置: 首页 > news >正文

ReentrantLock 源码深度解析

1. ReentrantLock 概述

ReentrantLock 是 Java 并发包中最重要的锁实现之一,它是一个可重入的互斥锁,具有与 synchronized 相同的基本行为和语义,但提供了更多的功能特性。

1.1 核心特性

  • 可重入性:同一个线程可以多次获取同一个锁
  • 公平性选择:支持公平锁和非公平锁两种模式
  • 可中断性:支持可中断的锁获取操作
  • 超时机制:支持带超时的锁获取尝试
  • 条件变量:支持多个条件变量(Condition)

1.2 类结构

public class ReentrantLock implements Lock, java.io.Serializable {private static final long serialVersionUID = 7373984872572414699L;/** Synchronizer providing all implementation mechanics */private final Sync sync;// 抽象同步器基类abstract static class Sync extends AbstractQueuedSynchronizer {// 非公平锁获取逻辑final boolean nonfairTryAcquire(int acquires);// 锁释放逻辑protected final boolean tryRelease(int releases);// 判断当前线程是否持有锁protected final boolean isHeldExclusively();// 创建条件变量final ConditionObject newCondition();}// 非公平锁实现static final class NonfairSync extends Sync {protected final boolean tryAcquire(int acquires);}// 公平锁实现static final class FairSync extends Sync {protected final boolean tryAcquire(int acquires);}
}

2. 核心设计原理

2.1 组合优于继承

ReentrantLock 采用了组合模式,将同步逻辑委托给内部的 Sync 对象:

/** Synchronizer providing all implementation mechanics */
private final Sync sync;

这种设计的优势:

  • 灵活性:可以动态选择公平锁或非公平锁
  • 可扩展性:易于添加新的锁策略
  • 职责分离:ReentrantLock 负责对外接口,Sync 负责同步逻辑

2.2 状态表示

ReentrantLock 使用 AQS 的 state 字段表示锁的持有次数:

  • state = 0:锁未被持有
  • state > 0:锁被持有,数值表示重入次数
  • state = 1:锁被持有一次
  • state = 2:锁被重入一次

3. 核心方法详解

3.1 锁获取方法

3.1.1 lock() - 基本锁获取
public void lock() {sync.acquire(1);
}

执行流程

  1. 调用 sync.acquire(1) 尝试获取锁
  2. 如果成功,直接返回
  3. 如果失败,线程进入等待队列,直到获取到锁

特点

  • 阻塞性:获取不到锁时会阻塞
  • 不可中断:不支持中断响应
  • 可重入:同一线程可以多次调用
3.1.2 lockInterruptibly() - 可中断锁获取
public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);
}

执行流程

  1. 检查当前线程是否被中断
  2. 如果已中断,抛出 InterruptedException
  3. 尝试获取锁,获取不到时进入等待队列
  4. 在等待过程中如果被中断,抛出 InterruptedException

特点

  • 响应中断:支持中断响应
  • 异常处理:需要处理 InterruptedException
  • 适用场景:需要响应中断的长时间等待
3.1.3 tryLock() - 尝试获取锁
public boolean tryLock() {return sync.nonfairTryAcquire(1);
}

执行流程

  1. 直接调用 nonfairTryAcquire(1) 尝试获取锁
  2. 成功返回 true,失败返回 false
  3. 不会阻塞,立即返回结果

重要特点

  • 不遵循公平性:即使设置了公平锁,tryLock() 也不会遵循公平原则
  • 立即返回:不会进入等待队列
  • 非阻塞:适合快速失败场景
3.1.4 tryLock(long timeout, TimeUnit unit) - 超时锁获取
public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

执行流程

  1. 将时间转换为纳秒
  2. 调用 tryAcquireNanos(1, nanos) 尝试获取锁
  3. 在指定时间内尝试获取,超时返回 false
  4. 支持中断响应

特点

  • 超时控制:避免无限等待
  • 中断响应:支持中断操作
  • 公平性遵循:会遵循公平锁的设置

3.2 锁释放方法

3.2.1 unlock() - 释放锁
public void unlock() {sync.release(1);
}

执行流程

  1. 调用 sync.release(1) 释放锁
  2. 如果当前线程不是锁持有者,抛出 IllegalMonitorStateException
  3. 减少持有计数,计数为 0 时完全释放锁

重要特点

  • 计数递减:每次调用减少持有计数 1
  • 完全释放:只有计数为 0 时才真正释放锁
  • 异常检查:非持有者调用会抛出异常

3.3 条件变量方法

3.3.1 newCondition() - 创建条件变量
public Condition newCondition() {return sync.newCondition();
}

执行流程

  1. 调用 sync.newCondition() 创建新的条件变量
  2. 返回 ConditionObject 实例
  3. 支持多个条件变量

使用示例

ReentrantLock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition();
Condition notFull = lock.newCondition();// 生产者-消费者模式
public void put(Object item) throws InterruptedException {lock.lock();try {while (queue.isFull()) {notFull.await(); // 等待不满条件}queue.put(item);notEmpty.signal(); // 通知不空条件} finally {lock.unlock();}
}

4. 公平锁与非公平锁

4.1 构造函数

// 默认非公平锁
public ReentrantLock() {sync = new NonfairSync();
}// 指定公平性
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();
}

4.2 非公平锁实现

4.2.1 NonfairSync.tryAcquire()
static final class NonfairSync extends Sync {protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}
}
4.2.2 nonfairTryAcquire() 核心逻辑
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 情况1:锁未被持有if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}// 情况2:当前线程已持有锁(重入)else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;
}

非公平锁特点

  • 抢占式:新来的线程可以直接尝试获取锁
  • 性能优先:减少线程切换,提高吞吐量
  • 饥饿可能:某些线程可能长时间获取不到锁

4.3 公平锁实现

4.3.1 FairSync.tryAcquire()
static final class FairSync extends Sync {protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 情况1:锁未被持有if (c == 0) {if (!hasQueuedPredecessors() &&  // 关键:检查是否有前驱节点compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}// 情况2:当前线程已持有锁(重入)else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
}

公平锁特点

  • FIFO 顺序:严格按照等待顺序获取锁
  • 公平性保证:避免饥饿现象
  • 性能略低:需要检查等待队列,性能略低于非公平锁
4.3.2 hasQueuedPredecessors() 方法
public final boolean hasQueuedPredecessors() {Node t = tail;Node h = head;Node s;return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}

判断逻辑

  1. h == t:队列为空,没有等待者
  2. h != t 且 s == null:有等待者但后继节点为空(异常情况)
  3. h != t 且 s.thread != currentThread:有等待者且不是当前线程

5. 锁释放机制

5.1 tryRelease() 实现

protected final boolean tryRelease(int releases) {int c = getState() - releases;// 检查当前线程是否是锁持有者if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;// 如果持有计数为 0,完全释放锁if (c == 0) {free = true;setExclusiveOwnerThread(null);}setState(c);return free;
}

释放逻辑

  1. 计数递减:state = state - releases
  2. 权限检查:只有持有者才能释放锁
  3. 完全释放:计数为 0 时清空持有线程
  4. 返回值:返回是否完全释放了锁

6. 状态查询方法

6.1 锁状态查询

// 查询锁是否被持有
public final boolean isLocked() {return sync.isLocked();
}// 查询当前线程是否持有锁
public boolean isHeldByCurrentThread() {return sync.isHeldExclusively();
}// 查询锁的持有次数
public int getHoldCount() {return sync.getHoldCount();
}// 查询锁的持有者
protected Thread getOwner() {return sync.getOwner();
}

6.2 队列状态查询

// 查询是否有线程等待获取锁
public final boolean hasQueuedThreads() {return sync.hasQueuedThreads();
}// 查询指定线程是否在等待队列中
public final boolean hasQueuedThread(Thread thread) {return sync.isQueued(thread);
}// 查询等待队列长度
public final int getQueueLength() {return sync.getQueueLength();
}// 获取等待线程集合
protected Collection<Thread> getQueuedThreads() {return sync.getQueuedThreads();
}

6.3 条件变量状态查询

// 查询指定条件上是否有等待线程
public boolean hasWaiters(Condition condition) {if (condition == null)throw new NullPointerException();if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))throw new IllegalArgumentException("not owner");return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}// 查询指定条件上等待线程的数量
public int getWaitQueueLength(Condition condition) {if (condition == null)throw new NullPointerException();if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))throw new IllegalArgumentException("not owner");return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}// 获取指定条件上等待的线程集合
protected Collection<Thread> getWaitingThreads(Condition condition) {if (condition == null)throw new NullPointerException();if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))throw new IllegalArgumentException("not owner");return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}

7. 使用最佳实践

7.1 基本使用模式

class X {private final ReentrantLock lock = new ReentrantLock();public void m() {lock.lock();  // 获取锁try {// ... 方法体} finally {lock.unlock();  // 确保锁被释放}}
}

7.2 可中断锁获取

public void m() throws InterruptedException {lock.lockInterruptibly();  // 可中断的锁获取try {// ... 方法体} finally {lock.unlock();}
}

7.3 超时锁获取

public boolean m(long timeout, TimeUnit unit) throws InterruptedException {if (lock.tryLock(timeout, unit)) {try {// ... 方法体return true;} finally {lock.unlock();}}return false;
}

7.4 条件变量使用

class BoundedBuffer {private final ReentrantLock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();private final Object[] items = new Object[100];private int putptr, takeptr, count;public void put(Object x) throws InterruptedException {lock.lock();try {while (count == items.length)notFull.await();items[putptr] = x;if (++putptr == items.length) putptr = 0;++count;notEmpty.signal();} finally {lock.unlock();}}public Object take() throws InterruptedException {lock.lock();try {while (count == 0)notEmpty.await();Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;notFull.signal();return x;} finally {lock.unlock();}}
}

8. 性能特点分析

8.1 公平锁 vs 非公平锁性能

特性公平锁非公平锁
吞吐量较低较高
延迟较高较低
公平性保证不保证
饥饿不会可能
适用场景对公平性要求高对性能要求高

8.2 性能优化建议

  1. 默认使用非公平锁:除非对公平性有特殊要求
  2. 减少锁持有时间:尽快释放锁
  3. 避免嵌套锁:防止死锁
  4. 合理使用条件变量:避免虚假唤醒

9. 与 synchronized 的对比

9.1 功能对比

特性ReentrantLocksynchronized
可中断性✅ 支持❌ 不支持
超时机制✅ 支持❌ 不支持
公平性✅ 可配置❌ 不可配置
条件变量✅ 多个❌ 单一
性能🟡 略高🟢 稳定
使用复杂度🟡 较高🟢 简单

9.2 选择建议

  • 使用 synchronized 的场景

    • 简单的同步需求
    • 对性能要求不是特别高
    • 希望代码简洁
  • 使用 ReentrantLock 的场景

    • 需要可中断锁获取
    • 需要超时机制
    • 需要公平锁
    • 需要多个条件变量
    • 对性能有较高要求

10. 总结

10.1 核心优势

  1. 功能丰富:提供比 synchronized 更多的功能
  2. 性能优秀:非公平锁模式下性能优于 synchronized
  3. 灵活配置:支持公平锁和非公平锁
  4. 可扩展性:基于 AQS,易于扩展

10.2 设计亮点

  1. 组合模式:通过组合 Sync 对象实现不同策略
  2. 模板方法:利用 AQS 的模板方法模式
  3. 状态管理:通过 state 字段管理重入次数
  4. 异常处理:完善的异常检查和处理

10.3 应用场景

  1. 高并发系统:需要高性能锁的场景
  2. 复杂同步:需要多个条件变量的场景
  3. 响应式编程:需要可中断锁获取的场景
  4. 超时控制:需要避免无限等待的场景

ReentrantLock 是 Java 并发编程中最重要的锁实现之一,它提供了比 synchronized 更丰富的功能和更好的性能,是构建高性能并发系统的首选工具。


文章转载自:

http://1e65qZQU.qgdsd.cn
http://93GsGWJ4.qgdsd.cn
http://Hr9nPIGX.qgdsd.cn
http://vWXHlvAe.qgdsd.cn
http://U3snjoB1.qgdsd.cn
http://UK9NHsQW.qgdsd.cn
http://bd6WpaMG.qgdsd.cn
http://Xa7Rggcm.qgdsd.cn
http://xAe05SX4.qgdsd.cn
http://T0zN1nk4.qgdsd.cn
http://TWEnlUgE.qgdsd.cn
http://nWvf99GJ.qgdsd.cn
http://IXRATE88.qgdsd.cn
http://FeqGWPgU.qgdsd.cn
http://ldfPkO5i.qgdsd.cn
http://RqfFWVd3.qgdsd.cn
http://QKM1bCi1.qgdsd.cn
http://FtvyaZnQ.qgdsd.cn
http://Tx7oE7CP.qgdsd.cn
http://bvUIKp71.qgdsd.cn
http://bQPPW13H.qgdsd.cn
http://w2LsLhRo.qgdsd.cn
http://RewXpkLk.qgdsd.cn
http://TyDuto03.qgdsd.cn
http://3deXnQYM.qgdsd.cn
http://FAzQJ2dm.qgdsd.cn
http://J7ufqldD.qgdsd.cn
http://4uKt5wVB.qgdsd.cn
http://utzI1K8e.qgdsd.cn
http://ECJauHLX.qgdsd.cn
http://www.dtcms.com/a/378187.html

相关文章:

  • 机器人驭风而行:低空经济如何开启智能新纪元
  • 【系统架构设计(27)】信息安全技术集成
  • spring mvc 拦截器 (HandlerInterceptor )
  • 【Nginx】- 日志定期清理设置
  • 102、23种设计模式之装饰器模式(11/23)
  • SwiftData3 一剑封喉:WWDC25 的“数据剑谱”精讲,让 Core Data 老侠原地退休
  • [硬件电路-180]:集成运放,在同向放大和反向放大电路中,失调电压与信号一起被等比例放大;但在跨阻运放中,失调电压不会与电流信号等比例放大。
  • IDEA连接redis数据库时出现Failed to connect to any host resolved for DNS name.
  • kafka:【2】工作原理
  • ctfshow_web14------(PHP+switch case 穿透+SQL注入+文件读取)
  • 中电金信携手海光推出金融业云原生基础设施联合解决方案
  • 【Linux】初始Linux:从计算机历史发展、操作系统历史脉络的角度详谈Linux相关的话题,附Linux安装和用户创建(环境准备)详解
  • 软件设计师_第十章:软件工程(上)
  • ptx 简介03,ldmatrix 的应用实例解析
  • CSS的平面转换transform
  • CSS 居中
  • Golang进阶(二):设计先行
  • 腾讯深夜“亮剑”,AI编程“王座”易主?CodeBuddy发布,Claude用户一夜倒戈
  • 突破机器人通讯架构瓶颈,CAN/FD、高速485、EtherCAT,哪种总线才是最优解?
  • 【开题答辩全过程】以 _基于SSM框架的植物园管理系统的实现与设计为例,包含答辩的问题和答案
  • 哈希表封装myunordered_map和myunordered_set
  • 9.9网编项目——UDP网络聊天室
  • 单表查询-having和where区别
  • LVGL:基础对象
  • 【LeetCode - 每日1题】将字符串中的元音字母排序
  • 签名、杂凑、MAC、HMAC
  • C++与QT高频面试问题(不定时更新)
  • 数据结构之跳表
  • 记录豆包的系统提示词
  • Docker 从入门到实践:容器化技术核心指南