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

面试八股之从Java到JVM层面深入解析ReentrantLock实现原理

一、ReentrantLock概述

ReentrantLock是Java并发包(java.util.concurrent.locks)中的一个重要组件,它是一个可重入的互斥锁,具有与synchronized关键字类似的功能,但提供了更灵活的锁操作。

基本特性

  • 可重入性:同一个线程可以多次获取同一把锁
  • 可中断:支持获取锁的过程中响应中断
  • 公平性选择:支持公平锁和非公平锁两种模式
  • 条件变量:支持多个条件队列

基本用法示例

ReentrantLock lock = new ReentrantLock();public void criticalSection() {lock.lock();  // 获取锁try {// 临界区代码} finally {lock.unlock();  // 释放锁}
}

二、ReentrantLock的JVM层面实现

1. 核心类结构

ReentrantLock的实现主要依赖于以下几个核心类:

  • AbstractQueuedSynchronizer (AQS):同步器框架基类
  • NonfairSync:非公平锁实现
  • FairSync:公平锁实现
public class ReentrantLock implements Lock, java.io.Serializable {private final Sync sync;abstract static class Sync extends AbstractQueuedSynchronizer {// 实现AQS的核心方法}static final class NonfairSync extends Sync {// 非公平锁实现}static final class FairSync extends Sync {// 公平锁实现}
}

2. AQS核心机制

AQS是ReentrantLock实现的核心,它维护了一个volatile int state变量和一个FIFO线程等待队列。

state变量含义
  • 0:锁未被任何线程持有

0:锁被某个线程持有,数值表示重入次数

等待队列
  • CLH队列的变种,用于实现线程的排队等待
  • 每个节点代表一个等待线程

3. 加锁过程分析

非公平锁实现
final void lock() {if (compareAndSetState(0, 1))  // 直接尝试CAS获取锁setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);  // 获取失败则进入AQS排队流程
}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);
}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) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;
}
公平锁实现
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&  // 检查是否有前驱节点compareAndSetState(0, acquires)) {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;
}

4. 解锁过程分析

public void unlock() {sync.release(1);
}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;
}

三、JVM层面的关键实现细节

1. CAS操作

ReentrantLock大量使用了CAS(Compare-And-Swap)操作,这是通过Unsafe类实现的:

protected final boolean compareAndSetState(int expect, int update) {return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

在JVM层面,CAS操作会被编译为特定平台的原子指令,如x86的cmpxchg指令。

2. 内存可见性

AQS中的state变量使用volatile修饰,保证了内存可见性:

private volatile int state;

在JVM层面:

  • 写volatile变量会插入StoreStore和StoreLoad内存屏障
  • 读volatile变量会插入LoadLoad和LoadStore内存屏障

3. 线程阻塞与唤醒

当线程获取锁失败时,会被park(阻塞):

LockSupport.park(this);

在JVM层面,这最终会调用到操作系统的线程调度机制:

  • Linux下使用pthread_cond_wait
  • Windows下使用WaitForSingleObject

当锁释放时,会unpark(唤醒)等待线程:

LockSupport.unpark(node.thread);

四、性能优化分析

1. 非公平锁的性能优势

非公平锁之所以性能更好,是因为:

  1. 减少了线程切换的开销
  2. 利用了线程的局部性原理
  3. 避免了频繁的上下文切换

2. 自旋优化

在进入park前,AQS会进行有限次数的自旋尝试,减少线程挂起的开销。

五、与synchronized的对比

特性

ReentrantLock

synchronized

实现层面

Java代码实现

JVM内置实现

锁获取方式

显式lock/unlock

隐式通过monitor进入/退出

可中断性

支持

不支持

公平性

可配置公平/非公平

完全非公平

条件变量

支持多个Condition

只有一个等待队列

性能

JDK1.6+优化后接近

JDK1.6+性能大幅提升

六、最佳实践

  1. 总是使用try-finally释放锁
lock.lock();
try {// 临界区代码
} finally {lock.unlock();
}
  1. 合理选择公平策略:默认使用非公平锁,除非有特殊需求
  2. 避免锁泄漏:确保锁在finally块中释放
  3. 考虑使用tryLock:避免死锁
if (lock.tryLock(1, TimeUnit.SECONDS)) {try {// 获取锁成功} finally {lock.unlock();}
} else {// 获取锁超时处理
}

七、总结

ReentrantLock是Java并发编程中的重要工具,它通过AQS框架实现了高效的可重入锁机制。从JVM层面看,它充分利用了CAS操作、volatile变量和线程调度机制,在保证线程安全的同时提供了良好的性能。

http://www.lryc.cn/news/618165.html

相关文章:

  • c++的四种类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast)详解和代码示例
  • 【R语言数据分析开发指南】
  • C++学习之数据结构:AVL树
  • 干货分享|如何从0到1掌握R语言数据分析
  • Rust:构造函数 new() 如何进行错误处理?
  • Vue.js 响应接口:深度解析与实践指南
  • 《Auracast广播音频技术解析及未来路线图》 —蓝牙技术联盟 市场拓展经理 吴志豪 技术与市场经理 鲁公羽
  • 基于 Easy Rules 的电商订单智能决策系统:构建可扩展的业务规则引擎实践
  • 电商双 11 美妆数据分析总结
  • CTO如何通过录音转写和音频降噪,提升企业远程协作效率?
  • 数据分析与可视化
  • 阿里巴巴开源多模态大模型-Qwen-VL系列论文精读(一)
  • Spring Cloud系列—Config配置中心
  • B树索引和B+树索引有什么区别?
  • TinyVue表格重构性能优化详解
  • 从基础编辑器到智能中枢:OpenStation 为 VSCode 注入大模型动力
  • 人工智能+虚拟仿真,助推医学检查技术理论与实践结合
  • MySQL 索引:索引为什么使用 B+树?(详解B树、B+树)
  • 零知开源——基于STM32F407VET6和INA219的功率监测器设计与实现
  • ZKmall开源商城的容灾之道:多地域部署与故障切换如何守护电商系统
  • 【新启航】从人工偏差到机械精度:旋转治具让三维扫描重构数据重复精度提升至 ±0.01mm
  • 解决 HTTP 请求 RequestBody 只能被读取一次的问题
  • 医美产业科技成果展陈中心:连接微观肌肤世界与前沿科技的桥梁
  • 【机器学习】什么是DNN / MLP(全连接深度神经网络, Deep Neural Network / Multilayer Perceptron)?
  • 01. maven的下载与配置
  • http网页部署
  • 微算法科技(NASDAQ:MLGO)开发经典增强量子优化算法(CBQOA):开创组合优化新时代
  • 聆思duomotai_ap sdk适配dooiRobot
  • 基于SpringBoot的课程作业管理系统
  • 【论文阅读】从表面肌电信号中提取神经信息用于上肢假肢控制:新兴途径与挑战