跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
ReentrantLock原理
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
{{Note|本文适用于Java初学者及需要理解并发编程核心机制的中级开发者。}} = ReentrantLock原理 = '''ReentrantLock'''是Java并发包(`java.util.concurrent.locks`)中提供的可重入互斥锁实现,相比`synchronized`关键字,它提供了更灵活的锁控制能力,支持公平性选择、可中断的锁获取、超时机制等高级特性。 == 核心特性 == * '''可重入性''':线程可以重复获取已持有的锁(通过计数器实现) * '''公平性选择''':支持公平锁(按等待顺序获取)和非公平锁(竞争获取) * '''锁中断''':通过`lockInterruptibly()`响应中断 * '''条件变量''':通过`Condition`实现精细化的线程通信 == 底层实现原理 == === 同步器(AQS)基础 === ReentrantLock基于'''AbstractQueuedSynchronizer(AQS)'''框架实现,其核心是通过一个volatile整型变量`state`表示锁状态: * <math>state = 0</math>:锁未被占用 * <math>state > 0</math>:锁被占用,数值表示重入次数 <mermaid> stateDiagram-v2 [*] --> Unlocked: state=0 Unlocked --> Locked: 线程获取锁 Locked --> Locked: 重入(state++) Locked --> Unlocked: 完全释放(state=0) </mermaid> === 获取锁流程(非公平模式) === 1. 尝试通过CAS修改state 2. 成功则设置独占线程为当前线程 3. 失败则进入AQS队列等待 === 释放锁流程 === 1. 减少重入计数器 2. 当state归零时: * 清除独占线程标记 * 唤醒队列中的等待线程 == 代码示例 == === 基础用法 === <syntaxhighlight lang="java"> import java.util.concurrent.locks.ReentrantLock; public class Counter { private final ReentrantLock lock = new ReentrantLock(); private int count = 0; public void increment() { lock.lock(); // 阻塞直到获取锁 try { count++; System.out.println("Count: " + count); } finally { lock.unlock(); // 必须手动释放 } } } </syntaxhighlight> {{Tip|务必在`finally`块中释放锁,防止异常导致死锁}} === 公平锁示例 === <syntaxhighlight lang="java"> ReentrantLock fairLock = new ReentrantLock(true); // 公平锁 public void accessResource() { fairLock.lock(); try { // 临界区代码 } finally { fairLock.unlock(); } } </syntaxhighlight> == 与synchronized对比 == {| class="wikitable" |- ! 特性 !! ReentrantLock !! synchronized |- | 实现方式 || API级实现 || JVM内置实现 |- | 锁获取方式 || 可非阻塞尝试(tryLock) || 仅阻塞获取 |- | 公平性 || 可配置 || 非公平 |- | 条件变量 || 支持多个Condition || 单一等待队列 |- | 锁释放 || 必须显式调用unlock() || 自动释放 |} == 高级特性 == === 锁中断 === <syntaxhighlight lang="java"> public void performTaskWithTimeout() throws InterruptedException { ReentrantLock lock = new ReentrantLock(); if (lock.tryLock(1, TimeUnit.SECONDS)) { // 超时等待 try { // 临界区 } finally { lock.unlock(); } } else { System.out.println("获取锁超时"); } } </syntaxhighlight> === 条件变量 === <syntaxhighlight lang="java"> class BoundedBuffer { final ReentrantLock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); void put(Object x) throws InterruptedException { lock.lock(); try { while (/* 缓冲区满 */) { notFull.await(); // 释放锁并等待 } // 放入数据 notEmpty.signal(); // 唤醒消费者 } finally { lock.unlock(); } } } </syntaxhighlight> == 性能考量 == * '''非公平锁'''(默认)通常吞吐量更高,但可能导致线程饥饿 * '''公平锁'''保证顺序性,但增加上下文切换开销 * 在激烈竞争场景下,ReentrantLock性能可能优于synchronized == 常见问题 == {{Q&A |问题 = 为什么需要可重入特性? |答案 = 避免线程因重复获取已持有的锁而导致死锁,例如递归调用场景。 }} {{Q&A |问题 = 如何选择公平/非公平模式? |答案 = 公平模式适用于需要严格顺序的场景,非公平模式适用于吞吐量优先场景。 }} == 实际应用案例 == '''电商库存扣减系统''': * 使用ReentrantLock保护共享库存数据 * 通过tryLock实现超时控制,避免系统雪崩 * 使用Condition实现库存不足时的等待/通知机制 {{Warning|不当使用可能导致: * 死锁(忘记释放锁) * 活锁(过度使用tryLock) * 性能下降(过长的临界区)}} == 总结 == ReentrantLock提供了比synchronized更精细的锁控制,适合需要高级特性的并发场景。理解其AQS实现原理有助于正确使用和性能调优。在简单场景下,仍推荐优先使用synchronized。 [[Category:计算机科学]] [[Category:面试技巧]] [[Category:Java并发编程]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)
该页面使用的模板:
模板:Mbox
(
编辑
)
模板:Note
(
编辑
)
模板:Q&A
(
编辑
)
模板:Tip
(
编辑
)
模板:Warning
(
编辑
)
模块:Arguments
(
编辑
)
模块:Message box
(
编辑
)
模块:Message box/ambox.css
(
编辑
)
模块:Message box/configuration
(
编辑
)
模块:Yesno
(
编辑
)