Java多线程知识梳理(3) 作者没有四次元口袋的蓝胖日期2026-07-06标签Java, 多线程, ReentrantLock, AQSJava多线程知识梳理(3)一、ReentrantLock 原理ReentrantLock可重入锁是 Java 并发包JUC中的核心类基于AQSAbstractQueuedSynchronizer实现功能比 synchronized 丰富得多。1.1 什么是可重入重入同一线程在外层获取锁后在内层再次获取同一把锁时不会死锁而是直接成功。ReentrantLocklocknewReentrantLock();publicvoidmethodA(){lock.lock();// 外层获取锁try{methodB();// 调用 B}finally{lock.unlock();// 外层释放锁}}publicvoidmethodB(){lock.lock();// 内层再次获取同一把锁 —— 如果不可重入就会死锁try{System.out.println(B);}finally{lock.unlock();// 必须成对释放}}ReentrantLock 通过维护一个state变量AQS 中的实现可重入第一次获取锁state 0 → 1同一线程重入state 1 → 2 → 3…每次释放锁state 递减到 0 时真正释放注意synchronized 也是可重入的通过对象头的 Mark Word 记录持有线程ID和重入次数。1.2 AQS 核心原理简述AQS 是 ReentrantLock 的底层骨架核心结构AQS ├── state同步状态int类型 ├── CLH 队列双向链表存储等待的线程 │ └── Node { thread, waitStatus, prev, next } └── 核心方法acquire()、release()、tryAcquire()、tryRelease()工作流程线程尝试获取锁失败则包装成 Node 加入 CLH 队列每个 Node 通过自旋或 park阻塞等待前驱节点的释放锁释放时唤醒队列中的下一个节点1.3 公平锁 vs 非公平锁ReentrantLockfairLocknewReentrantLock(true);// 公平锁ReentrantLockunfairLocknewReentrantLock(false);// 非公平锁默认对比公平锁非公平锁获取顺序严格按 FIFO 顺序允许插队CAS 尝试获取性能较低要维护队列顺序较高减少线程切换饥饿不会新线程可能抢到锁导致等待久的线程延迟实现区别获取锁时必须检查队列中是否有等待线程直接 CAS 抢锁抢不到才进队列非公平锁获取流程线程来了直接 CAS 尝试抢锁不排队抢到 → 返回成功抢不到 → 检查 state如果是可重入则直接获取否则加入 CLH 队列尾部等待公平锁获取流程线程来了先检查队列是否为空队列不为空 → 老老实实排到队尾队列为空 → 才尝试 CAS 抢锁 绝大多数场景用非公平锁性能更好。公平锁只有在对响应时间公平性有严格要求时才使用。1.4 ReentrantLock 的常用方法方法说明lock()阻塞式获取锁不可中断lockInterruptibly()可中断获取锁等待时响应中断tryLock()非阻塞尝试获取锁立即返回 true/falsetryLock(long time, TimeUnit unit)指定时间内尝试获取超时返回 falseunlock()释放锁必须在 finally 中调用isLocked()查询当前是否有线程持有锁getHoldCount()查询当前线程重入次数1.5 正确用法模板ReentrantLocklocknewReentrantLock();publicvoiddoSomething(){lock.lock();// 必须在 try 之外try{// 临界区代码}finally{lock.unlock();// 必须 finally 释放否则异常时永远锁死}}// 可中断版本publicvoiddoSomethingInterruptible(){try{lock.lockInterruptibly();try{// 临界区代码}finally{lock.unlock();}}catch(InterruptedExceptione){Thread.currentThread().interrupt();}}⚠️常见坑lock() 放在 try 里如果 lock() 本身抛异常finally 中的 unlock() 会释放一个没被持有的锁导致 IllegalMonitorStateException。二、ReentrantLock vs synchronized 深度对比对比维度synchronizedReentrantLock实现层面JVM 关键字monitorenter/monitorexitJDK API基于 AQS锁释放JVM 自动释放必须手动 unlock()放在 finally可中断不可中断阻塞等可中断lockInterruptibly超时获取不支持tryLock(time)尝试获取不支持tryLock() 非阻塞公平性非公平可选公平/非公平条件变量只有一个Object 的 wait/notify可绑定多个 Condition锁升级有无锁→偏向→轻量级→重量级无直接重量级性能JDK6 后优化锁升级略低于优化后的 synchronized代码简洁性简洁关键字即可繁琐必须 try-finally2.1 什么时候选谁选 synchronized简单的同步代码块/方法对性能要求不高、代码简洁优先不需要特殊锁功能选 ReentrantLock需要公平锁需要响应中断 / 超时获取需要 tryLock 非阻塞尝试需要多个 Condition如生产者-消费者模式需要细粒度的锁控制 阿里 Java 开发手册强制要求在使用锁时优先选择 Lock 接口ReentrantLock因为其功能更丰富。2.2 Condition更细粒度的条件控制ReentrantLocklocknewReentrantLock();ConditionnotFulllock.newCondition();// 生产者等待ConditionnotEmptylock.newCondition();// 消费者等待// 生产者lock.lock();try{while(isFull())notFull.await();// 满则等待produce();notEmpty.signal();// 生产后通知消费者}finally{lock.unlock();}// 消费者lock.lock();try{while(isEmpty())notEmpty.await();// 空则等待consume();notFull.signal();// 消费后通知生产者}finally{lock.unlock();}Object 的 wait/notify/notifyAll 只能配合单一锁而 Condition 可以有多个实现更精细的线程调度如 ArrayBlockingQueue 的实现。三、思维导图速览┌───────────────────────────────────────────────────┐ │ ReentrantLock 深度解析 │ ├───────────────────────────────────────────────────┤ │ │ │ 底层AQSAbstractQueuedSynchronizer │ │ • state同步状态int │ │ • CLH 队列双向链表存储等待线程 │ │ │ │ 可重入实现 │ │ • state 计数0→1→2... 释放时递减 │ │ • synchronized 也可重入Mark Word 记录 │ │ │ │ 公平锁 vs 非公平锁 ⭐⭐⭐⭐⭐ │ │ • 公平锁先检查队列严格按FIFO │ │ • 非公平锁直接CAS抢性能更好 │ │ │ │ 常用方法 │ │ • lock / lockInterruptibly │ │ • tryLock / tryLock(time) │ │ • unlock必须 finally │ │ │ │ Condition多条件变量 ⭐⭐⭐⭐ │ │ • 比 wait/notify 更精细 │ │ • 典型生产者-消费者notFull/notEmpty │ │ │ │ vs synchronized ⭐⭐⭐⭐⭐ │ │ • 实现JVM vs JDK │ │ • 释放自动 vs 手动 │ │ • 功能简单 vs 丰富中断/超时/公平/多Condition│ └───────────────────────────────────────────────────┘四、写在最后AQS 是 JUC 的核心骨架理解 AQS 才能理解 ReentrantLock、CountDownLatch、Semaphore 等所有并发工具后续学习 CountDownLatch 时会更容易ReentrantLock vs synchronized是面试高频对比题要能清晰说出 6-8 个对比维度lock() 必须放在 try 之外这个细节很容易被忽略手写代码时要注意

相关新闻

最新新闻

3 款主流模拟器抓包对比:逍遥/雷电/夜神运行支付宝小程序成功率实测

3 款主流模拟器抓包对比:逍遥/雷电/夜神运行支付宝小程序成功率实测

3款主流安卓模拟器抓包能力深度评测:逍遥/雷电/夜神运行支付宝小程序实战分析移动应用安全测试和逆向分析工作中,抓包是最基础却也是最关键的环节。对于支付宝小程序这类采用严格安全措施的应用,选择合适的模拟器环境往往能事半功倍。本文将针…

2026/7/7 9:37:23
Next.js ISR 与生活数据缓存:增量更新不是全量刷新的替代品

Next.js ISR 与生活数据缓存:增量更新不是全量刷新的替代品

Next.js ISR 与生活数据缓存:增量更新不是全量刷新的替代品 一、生活数据页面的缓存需求比电商更特殊 Next.js 的 ISR(Incremental Static Regeneration)常用于电商和内容站点的页面缓存。商品页面更新频率低、访问量大,ISR 的按需…

2026/7/7 9:37:23
十字军之王II终极双字节补丁:完整中文显示解决方案

十字军之王II终极双字节补丁:完整中文显示解决方案

十字军之王II终极双字节补丁:完整中文显示解决方案 【免费下载链接】CK2dll Crusader Kings II double byte patch /production : 3.3.4 /dev : 3.3.4 项目地址: https://gitcode.com/gh_mirrors/ck/CK2dll 还在为《十字军之王II》中的中文乱码而烦恼吗&…

2026/7/7 9:37:23
3大模块掌握OpenRocket:从火箭设计到高精度仿真的完整工作流

3大模块掌握OpenRocket:从火箭设计到高精度仿真的完整工作流

3大模块掌握OpenRocket:从火箭设计到高精度仿真的完整工作流 【免费下载链接】openrocket Model-rocketry aerodynamics and trajectory simulation software 项目地址: https://gitcode.com/GitHub_Trending/op/openrocket OpenRocket作为一款开源的模型火箭…

2026/7/7 9:37:23
异步 RAG 流水线:embedding、检索与生成分阶段并发的实现细节

异步 RAG 流水线:embedding、检索与生成分阶段并发的实现细节

异步 RAG 流水线:embedding、检索与生成分阶段并发的实现细节 一、深度引言与场景痛点 先给你看一组数字:一个典型的 RAG 查询,embedding 耗时约 150ms,向量检索耗时约 80ms,rerank 耗时约 200ms,LLM 生成耗…

2026/7/7 9:37:23
企业微信UI自动化测试:PO设计模式实战与分层架构详解

企业微信UI自动化测试:PO设计模式实战与分层架构详解

1. 项目概述:为什么UI自动化离不开PO模式?做UI自动化测试的朋友,尤其是用过Selenium、Playwright这类工具的人,一定有过这样的体验:脚本刚写完时跑得挺顺,可一旦页面元素改个ID、加个class,或者…

2026/7/7 9:32:23

月新闻