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

ReentrantLock 原理

ReentrantLock本质通过AQS同步器实现,结合AQS认识ReentrantLock。
在这里插入图片描述

非公平锁实现原理

在这里插入图片描述

在这里插入图片描述

竞争失败后会执行执行ReentrantLock实现的acquire方法,在JDK11中,acquire直接由AQS实现了。

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Mode.EXCLUSIVE), arg))selfInterrupt();
}

addWaiter(Mode.EXCLUSIVE)

在这里插入图片描述

acquireQueued

shouldParkAfterFailedAcquire,-1节点负责唤醒后面的紧挨的0节点。

final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

parkAndCheckInterrupt

private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();
}

在这里插入图片描述

在这里插入图片描述

Thread-0 释放锁,进入 tryRelease 流程

public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;
}

释放锁成功,继续执行acquireQueued

在这里插入图片描述

在这里插入图片描述

可重入原理

重入一次state+1,释放一次state-1,直到state=0,setExclusiveOwnerThread(null)。

static final class NonfairSync extends Sync {//...// Sync 继承过来的方法,方便阅读,放在此处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()) {// state++int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
}
// Sync 继承过来的方法,方便阅读,放在此处
protected final boolean tryRelease(int releases) {// state-- 1 -1int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;// 支持锁重入,只有 state 减为 0, 才释放成功if (c == 0) {free = true;setExclusiveOwnerThread(null);}setState(c);return free;
}

可打断原理(默认)

在此模式下,即使它被打断,仍会驻留在AQS队列中,等获得锁后方能继续运行(是继续运行!只是打断标记被设置为 true)

被打断后,return Thread.interrupted();重置标志位,返回true。parkAndcheckInterrupt()返回真,interrupted记录打断标志,获得到锁后,acquireQueued(addWaiter(Node.EXCLUSIVE), arg)为真,执行selfInterrupt();重新产生一个中断。

所以在队列排队时,不能立刻响应中断,需要获得锁后才能打断。事实上被打断你是一定要作出回应的,这里在队列里时不回应,在获取到锁后进行一次补偿回应。所以获取到锁后进行打断。

// Sync 继承自 AQS
static final class NonfairSync extends Sync {//...private final boolean parkAndCheckInterrupt() {// 如果打断标记已经是 true, 则 park 会失效LockSupport.park(this);// interrupted 会清除打断标记return Thread.interrupted();}final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null;failed = false;// 还是需要获得锁后,才能返回打断状态return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt()) {// 如果是因为 interrupt 被唤醒,返回打断状态为 trueinterrupted = true;}}} finally {if (failed)cancelAcquire(node);}public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {// 如果打断状态为 trueselfInterrupt();}}static void selfInterrupt() {// 重新产生一次中断Thread.currentThread().interrupt();}
}

可打断模式

尝试获取锁调用acquireInterruptibly而不是acquire,acquire的打断后置标志位变为acquireInterruptibly的抛出异常throw new InterruptedException();。

static final class NonfairSync extends Sync {public final void acquireInterruptibly(int arg) throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();// 如果没有获得到锁,进入 (一)if (!tryAcquire(arg))doAcquireInterruptibly(arg);}// (一) 可打断的获取锁流程private void doAcquireInterruptibly(int arg) throws InterruptedException {final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt()) {// 在 park 过程中如果被 interrupt 会进入此// 这时候抛出异常,而不会再次进入 for (;;)throw new InterruptedException();}}} finally {if (failed)cancelAcquire(node);}}
}

非公平锁原理

获取锁调用nonfairTryAcquire直接参与锁的竞争compareAndSetState(0, acquires),不检查等待队列是否有任务。

// (三) Sync 继承过来的方法,方便阅读,放在此处
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 如果还没获得锁if (c == 0) {// 尝试用 cas 获得,这里体现了非公平性: 不去检查 AQS 队列if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}// 如果已经获得了锁,线程还是当前线程,表示发生了锁重入else if (current == getExclusiveOwnerThread()) {// state++int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}// 获取失败,回到调用处return false;
}

公平锁原理

获取锁时调用tryAcquire,检查等待队列是否有任务。

// 与非公平锁主要区别在于 tryAcquire 方法的实现
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 先检查 AQS 队列中是否有前驱节点,没有才去竞争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;
}// (一) AQS 继承过来的方法,方便阅读,放在此处
public final boolean hasQueuedPredecessors() {Node t = tail;Node h = head;Node s;// h != t 时表示队列中有 Nodereturn h != t &&(// (s = h.next) == null 表示队列中还有没有老二(s = h.next) == null ||// 或者队列中老二线程不是此线程s.thread != Thread.currentThread());
}

条件变量实现原理

await流程

public final void await() throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();Node node = addConditionWaiter();int savedState = fullyRelease(node);int interruptMode = 0;while (!isOnSyncQueue(node)) {LockSupport.park(this);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;if (node.nextWaiter != null) // clean up if cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);
}private Node addConditionWaiter() {Node t = lastWaiter;// If lastWaiter is cancelled, clean out.if (t != null && t.waitStatus != Node.CONDITION) {unlinkCancelledWaiters();t = lastWaiter;}Node node = new Node(Thread.currentThread(), Node.CONDITION);if (t == null)firstWaiter = node;elset.nextWaiter = node;lastWaiter = node;return node;
}// fullyRelease是对锁重入次数的全部释放,包括可重入锁
final int fullyRelease是对锁的全部释放,包括可重入锁(Node node) {boolean failed = true;try {int savedState = getState();if (release(savedState)) {failed = false;return savedState;} else {throw new IllegalMonitorStateException();}} finally {if (failed)node.waitStatus = Node.CANCELLED;}
}public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;
}

在这里插入图片描述

在这里插入图片描述
Thread-0执行LockSupport.park(this);阻塞。t条件变量的Node为-2为等待状态Node.CONDITION。

在这里插入图片描述

signal 流程

public final void signal() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignal(first);
}

isHeldExclusively判断是否是占用锁的线程,doSignal(first);会获取在条件变量中等待的队列中的第一个。

在这里插入图片描述

private void doSignal(Node first) {do {if ((firstWaiter = first.nextWaiter) == null)lastWaiter = null;first.nextWaiter = null;} while (!transferForSignal(first) && (first = firstWaiter) != null);
}

更新条件变量中等待的队列的指针指向,transferForSignal将唤醒的队列加入到等待锁的队列中,转移失败则唤醒条件变量中下一个任务。转移失败原因:如任务等待超时放弃对锁的使用。

在这里插入图片描述

enq(node)执行转移逻辑,返回前驱节点p,通过p.waitStatus将前驱节点转为-1状态,让前驱节点有责任唤醒后继节点。

在这里插入图片描述

http://www.xdnf.cn/news/1079587.html

相关文章:

  • Euler2203安装.NetCore6.0环境操作步骤
  • 前端单元测试覆盖率工具有哪些,分别有什么优缺点
  • Java中的volatile到底是什么来路
  • RAG实战指南 Day 4:LlamaIndex框架实战指南
  • CentOS系统高效部署fastGPT全攻略
  • 21、MQ常见问题梳理
  • 【论】电力-交通融合网协同优化:迎接电动汽车时代的挑战
  • thinkphp8接管异常处理类
  • 【第三章:神经网络原理详解与Pytorch入门】01.神经网络算法理论详解与实践-(2)神经网络整体结构
  • STM32-第二节-GPIO输入(按键,传感器)
  • C盘爆满元凶!WinSxS组件解密
  • JsonCpp的核心类及核心函数使用汇总
  • Web 服务器架构选择深度解析
  • Linux常见指令以及权限理解
  • Flowable12基础流程实战资金申请------------持续更新中
  • 埃及黑白沙漠:2亿年风蚀岩的“外星登陆现场“
  • 未来之窗冥界调试工具—东方仙盟
  • LTspice仿真10——电容
  • A模块 系统与网络安全 第四门课 弹性交换网络-1
  • 在小程序中实现实时聊天:WebSocket最佳实践
  • Verilog 语法介绍 1-1结构
  • Spring Boot + 本地部署大模型实现:基于 Ollama 的集成实践
  • KMP(Kotlin Multiplatform)改造(Android/iOS)老项目
  • PHP语法基础篇(八):超全局变量
  • 转录组分析流程(零):流程介绍
  • 【二分】-----【Music Notes S】
  • 【Git】同时在本地使用多个github账号进行github仓库管理
  • 通过Curtain 解决方案保障BIM模型安全共享—建筑业的防泄密实战
  • react-打包和本地预览 ——打包优化
  • 【数据结构】C++的unordered_map/set模拟实现(开散列(哈希桶)作底层)