JAVA锁 —— ReentrantLock公平锁和非公平锁原理详解

发布时间:2026/11/7 0:41:22

JAVA锁  ——  ReentrantLock公平锁和非公平锁原理详解 一、简介ReentrantLock的实现是基于其内部类FairSync(公平锁)和NonFairSync(非公平锁)实现的。 其可重入性是基于Thread.currentThread()实现的如果当前线程已经获得了执行序列中的锁 那执行序列之后的所有方法都可以获得这个锁。1、公平锁公平和非公平锁的队列都基于锁内部维护的一个双向链表表结点Node的值就是每一个请求当前锁的线程。公平锁则在于每次都是依次从队首取值。锁的实现方式是基于如下几点1、表结点Node和状态state的volatile关键字。2、sum.misc.Unsafe.compareAndSet的原子操作(见附录)2、非公平锁在等待锁的过程中 如果有任意新的线程妄图获取锁都是有很大的几率直接获取到锁的。ReentrantLock锁都不会使得线程中断除非开发者自己设置了中断位。ReentrantLock获取锁里面有看似自旋的代码但是它不是自旋锁。ReentrantLock公平与非公平锁都是属于排它锁。二、ReentrantLock的可重入性分析ReentrantLock重入性是基于Thread.currentThread()实现的: 如果当前线程已经获得了锁 那该线程下的所有方法都可以获得这个锁。ReentrantLock的锁依赖只有 NonfairSync和FairSync两个实现类 他们的锁获取方式大同小异。//可重入性的实现基于下面代码片段的 else if 语句 protected final boolean tryAcquire(int acquires) { final Thread current Thread.currentThread(); int c getState(); if (c 0) { ... // 尝试获取锁成功 } else if (current getExclusiveOwnerThread()) { // 是当前线程直接获取到锁。实现可重入性。 int nextc c acquires; if (nextc 0) throw new Error(Maximum lock count exceeded); setState(nextc); return true; } return false; }此处有两个值需要关心//持有该锁的当前线程 private transient Thread exclusiveOwnerThread; -----------------两个值不在同一个类---------------- /** * 同步状态 * 0 初始状态-无任何线程得到了锁 * 0: 被线程持有 具体值表示被当前线程持有的执行次数 * 这个字段在解锁的时候也需要用到。 * 注意这个字段的修饰词: volatile */ private volatile int state;三、ReentrantLock锁的实现分析1、公平锁和非公平锁ReentrantLock 的公平锁和非公平锁都委托了AbstractQueuedSynchronizer#acquire去请求获取。public final void acquire(int arg) { if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }tryAcquire是一个抽象方法是公平与非公平的实现原理所在。addWaiter 是将当前线程结点加入等待队列之中。公平锁在锁释放后会严格按照等到队列去取后续值而非公平锁在对于新晋线程有很大优势。acquireQueued在多次循环中尝试获取到锁或者将当前线程阻塞。selfInterrupt如果线程在阻塞期间发生了中断调用Thread.currentThread().interrupt()中断当前线程。ReentrantLock 对线程的阻塞是基于LockSupport.park(this); (AbstractQueuedSynchronizer#parkAndCheckInterrupt先决条件是当前节点有限次尝试获取锁失败。公平锁和非公平锁在锁的获取上都使用到了volatile 关键字修饰的state字段 这是保证多线程环境下锁的获取与否的核心。但是当并发情况下多个线程都读取到 state 0时则必须用到CAS技术一门CPU的原子锁技术可通过CPU对共享变量加锁的形式实现数据变更的原子操作。volatile 和 CAS的结合是并发抢占的关键。2、公平锁FairSync公平锁的实现机理在于每次有线程来抢占锁的时候都会检查一遍有没有等待队列如果有 当前线程会执行如下步骤if (!hasQueuedPredecessors() compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; }其中hasQueuedPredecessors是用于检查是否有等待队列的。public final boolean hasQueuedPredecessors() { Node t tail; // Read fields in reverse initialization order Node h head; Node s; return h ! t ((s h.next) null || s.thread ! Thread.currentThread()); }3、非公平锁NonfairSync非公平锁在实现的时候多次强调随机抢占if (c 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } }与公平锁的区别在于新晋获取锁的进程会有多次机会去抢占锁。如果被加入了等待队列后则跟公平锁没有区别。4、ReentrantLock锁的释放ReentrantLock锁的释放是逐级释放的也就是说在可重入性场景中必须要等到场景内所有的加锁的方法都释放了锁 当前线程持有的锁才会被释放。释放的方式很简单 state字段减一即可protected final boolean tryRelease(int releases) { // releases 1 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; }5、ReentrantLock等待队列中元素的唤醒当前拥有锁的线程释放锁之后 且非公平锁无线程抢占就开始线程唤醒的流程。通过tryRelease释放锁成功调用LockSupport.unpark(s.thread); 终止线程阻塞。private void unparkSuccessor(Node node) { // 强行回写将被唤醒线程的状态 int ws node.waitStatus; if (ws 0) compareAndSetWaitStatus(node, ws, 0); Node s node.next; // s为h的下一个Node, 一般情况下都是非Null的 if (s null || s.waitStatus 0) { s null; // 否则按照FIFO原则寻找最先入队列的并且没有被Cancel的Node for (Node t tail; t ! null t ! node; t t.prev) if (t.waitStatus 0) s t; } // 再唤醒它 if (s ! null) LockSupport.unpark(s.thread); }6、ReentrantLock内存可见性分析try { lock.lock(); i ; } finally { lock.unlock(); }可以发现哪怕在不使用 volatile关键字修饰元素i的时候 这里的i 也是没有并发问题的。volatile 是Java语言的关键字 功能是保证被修饰的元素(共享变量)任何进程在读取的时候都会清空本进程里面持有的共享变量的值强制从主存里面获取任何进程在写入完毕的时候都会强制将共享变量的值写会主存。volatile 会干预指令重排。volatile 实现了JMM规范的 happen-before 原则。并发编程之ReentrantLock公平锁和非公平锁原理详解
延伸阅读

更多相关文章

2026/11/6 7:39:21

177、镜头设计进阶:自由曲面镜头在超广角与畸变校正中的工程实践

177、镜头设计进阶:自由曲面镜头在超广角与畸变校正中的工程实践 去年有个车载项目让我印象深刻——客户要求前视摄像头做到120视场角,同时畸变控制在1%以内。当时团队里光学工程师直接拍桌子说“传统球面镜组做不到”,后来我们硬是用自由曲面镜头把这事给啃下来了。今天聊聊…

2026/11/5 16:09:30

179、去马赛克算法对比:从双线性插值到深度学习驱动的方向自适应方法

179、去马赛克算法对比:从双线性插值到深度学习驱动的方向自适应方法 一、一个让我熬夜三天的Bayer Raw问题 2018年做某款旗舰机前置摄像头调试,Sensor输出是Quad Bayer排列,ISP端用了某家主流平台的默认去马赛克算法。白天场景一切正常,一到黄昏室内灯光下,人物头发边缘…

2026/10/27 3:54:34

RAG召回率95%却答错?Taotoken实测:问题出在重排阶段的3个隐形门槛

金融知识库RAG系统优化实战:从高召回到高准确率的跃迁 上周我们上线了金融知识库RAG系统后遇到的挑战与解决方案,值得深入探讨。这个案例揭示了现代RAG系统在实际业务落地中的复杂性和优化空间。 现象剖析:高召回≠可用答案的深层原因 在金…

2026/11/7 16:04:53

椒江电工证年审有效期多久值不值得考

椒江电工证年审有效期多久值不值得考 你是不是正愁找不到工作?别急, 特种作业证 就是你上岗的“通行证”,尤其是 椒江电工证年审 ,直接决定你能不能进入工地、工厂、维修岗这些高需求岗位。今天就来聊聊这个证到底 值不值得考 ,特别是对…

2026/11/7 16:04:53

修空调要考电工证了吗保姆级教程

修空调要考电工证了吗保姆级教程 怕考不过白交培训费?别慌,今天手把手带你搞懂【修空调要考电工证了吗】这事儿,从报考条件、考试流程、实操技巧,再到证书价值和未来晋升,全是干货, 保姆级教程 ,看完直接上手。 修空调必须考电工证吗?…

2026/11/7 16:04:53

广州中级电工证有用吗 考证多久拿证全解析

广州中级电工证有用吗 考证多久拿证全解析 学历不高怕报不上名?广州中级电工证有用吗?我见过太多人因为学历问题犹豫要不要考,结果错过机会。今天就来聊聊这个事,告诉你广州中级电工证到底有没有用,怎么考,多久能拿证,特别是像你这样学历不高但想进电…

2026/11/7 15:59:53

电工证标志牌值不值得考?安阳应届生求职避坑全攻略

电工证标志牌值不值得考?安阳应届生求职避坑全攻略 你是不是也像我一样,刚毕业就急着找工作,却发现很多岗位都要求持证上岗? 电工证标志牌 就是其中之一。这个证不仅是你能力的证明,更是你能不能顺利找到工作的“通行证”。但问题是,…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/7 0:03:08

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科 实操考试心里没底怕挂科?你不是一个人。特别是在郑州这样的城市,很多施工企业负责人和一线作业人员在报考电工证和钳工证时都面临着同样的困惑。到底该考哪个证?哪个更适合自己?哪个证书…

2026/11/7 0:03:08

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱?

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱? 之前考的证在外省能不能转过来?这个问题我遇到太多了,今天就拿广西电工证办理流程来具体说说,别再走弯路了。广西电工证的报考、复审、继续教育这些环节,如果你不了解,真的会吃大亏,尤其对于从…

2026/11/7 0:03:08

电气电工证都有哪些保姆级教程

电气电工证都有哪些保姆级教程 你是不是正愁不知道去哪报名,怕被中介坑?别急,这篇保姆级教程专为河南初次报考人员准备,帮你搞清楚 电气电工证都有哪些 ,以及如何避开那些坑。 电气电工证都有哪些?别被五花八门的证书搞懵了…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑