一、Condition的await()方法底层源码

以下是 ConditionObject 中 await 方法的源码及其详细分析:

public final void await() throws InterruptedException {
// 判断当前线程是否是中断状态,是就直接给个中断异常
if (Thread.interrupted())
throw new InterruptedException(); // 将调用 await 的线程包装成 Node,添加到 Condition条件队列并返回
Node node = addConditionWaiter(); // 完全释放节点持有的锁,因为其他线程唤醒当前线程的前提是【持有锁】
int savedState = fullyRelease(node); // 设置打断模式为没有被打断,状态码为 0
int interruptMode = 0; // 如果该节点还没有转移至 AQS 阻塞队列, park 阻塞,等待进入 AQS阻塞队列
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
// 如果被打断,退出等待队列,对应的 node 【也会被迁移到 AQS阻塞队列】尾部,状态设置为 0
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
} // 逻辑到这说明当前线程退出 Condition条件队列,进入【AQS阻塞队列】 // 尝试枪锁,获取锁成功判断打断模式
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT; // node 在Condition条件队列时 如果被外部线程中断唤醒,会加入到 AQS阻塞队列,但是并未设 nextWaiter = null
if (node.nextWaiter != null)
// 清理条件队列内所有已取消的 Node
unlinkCancelledWaiters(); // 条件成立说明挂起期间发生过中断
if (interruptMode != 0)
// 应用打断模式
reportInterruptAfterWait(interruptMode);
}

二、await 方法的详细步骤解析

1、检查线程中断状态

  • Thread.interrupted():检查当前线程是否已被中断。如果已被中断,抛出 InterruptedException。

2、创建等待节点

  • addConditionWaiter():将当前线程封装为一个 Node 节点,并加入到 Condition 的等待队列中。

    • Condition 的等待队列是一个单向链表,每个节点代表一个等待线程。

    • 新节点会被添加到链表的尾部。

3、释放锁

  • fullyRelease(node):完全释放与 Condition 关联的锁。

    • 调用 AQS 的 release 方法,释放锁并唤醒后继节点。

    • 保存当前的锁状态(savedState),以便后续重新获取锁。

4、阻塞线程

  • isOnSyncQueue(node):检查当前节点是否在同步队列中。

    • 如果节点不在同步队列中,调用 LockSupport.park(this) 阻塞当前线程。

    • 线程被阻塞后,会一直等待,直到被其他线程调用 signal 或 signalAll 唤醒,或者被中断。

5、处理中断

  • checkInterruptWhileWaiting(node):检查线程是否在等待过程中被中断。

    • 如果被中断,返回中断模式(THROW_IE 或 REINTERRUPT)。

    • THROW_IE:表示在等待过程中被中断,需要抛出 InterruptedException。

    • REINTERRUPT:表示在唤醒后被中断,需要重新设置中断状态。

6、重新获取锁

  • acquireQueued(node, savedState):线程被唤醒后,重新尝试获取锁。

    • 如果获取锁成功,返回 true。

    • 如果获取锁失败,线程会继续阻塞,直到获取锁。

7、清理取消的等待节点

  • unlinkCancelledWaiters():清理等待队列中已取消的节点。

  • 遍历等待队列,移除状态为 CANCELLED 的节点。

8、报告中断状态

  • reportInterruptAfterWait(interruptMode):根据中断模式处理中断状态。

    • 如果中断模式为 THROW_IE,抛出 InterruptedException。

    • 如果中断模式为 REINTERRUPT,重新设置线程的中断状态。

Condition的await()方法底层源码的更多相关文章

  1. AspNetCore底层源码剖析(三)IOC

    title: AspNetCore底层源码剖析(三)IOC date: 2022-09-21 13:20:01 categories: 后端 tags: - .NET 介绍 每个 ASP.NET Co ...

  2. Android开发之漫漫长途 Ⅵ——图解Android事件分发机制(深入底层源码)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  3. 为什么很多类甚者底层源码要implements Serializable ?

    为什么很多类甚者底层源码要implements Serializable ? 在碰到异常类RuntimeException时,发现Throwable实现了 Serializable,还有我们平进的ja ...

  4. List-LinkedList、set集合基础增强底层源码分析

    List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...

  5. 从底层源码浅析Mybatis的SqlSessionFactory初始化过程

    目录 搭建源码环境 POM依赖 测试SQL Mybatis全局配置文件 UserMapper接口 UserMapper配置 User实体 Main方法 快速进入Debug跟踪 源码分析准备 源码分析 ...

  6. Java泛型底层源码解析-ArrayList,LinkedList,HashSet和HashMap

    声明:以下源代码使用的都是基于JDK1.8_112版本 1. ArrayList源码解析 <1. 集合中存放的依然是对象的引用而不是对象本身,且无法放置原生数据类型,我们需要使用原生数据类型的包 ...

  7. 2018.11.20 Struts2中对结果处理方式分析&struts2内置的方式底层源码剖析

    介绍一下struts2内置帮我们封装好的处理结果方式也就是底层源码分析 这是我们的jar包里面找的位置目录 打开往下拉看到result-type节点 name那一列就是我们的type类型取值 上一篇博 ...

  8. HashMap和ConcurrentHashMap的区别,HashMap的底层源码

    HashMap本质是数组加链表,根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap在HashMap的基础 ...

  9. 总结HashSet以及分析部分底层源码

    总结HashSet以及分析部分底层源码 1. HashSet继承的抽象类和实现的接口 继承的抽象类:AbstractSet 实现了Set接口 实现了Cloneable接口 实现了Serializabl ...

  10. LInkedList总结及部分底层源码分析

    LInkedList总结及部分底层源码分析 1. LinkedList的实现与继承关系 继承:AbstractSequentialList 抽象类 实现:List 接口 实现:Deque 接口 实现: ...

随机推荐

  1. 第一个shell脚本(bash脚本)

    首先它是一个脚本,并不能作为正式的编程语言.因为是跑在linux的shell中,所以叫shell脚本.说白了,shell脚本就是一些命令的集合.运维工作中把常用的一系列的操作都记录到一个文档中,然后去 ...

  2. 微软宣布更新SymCrypt加密库,新增对PQC算法的支持

    转载链接:https://mp.weixin.qq.com/s/aWXzPTWhxFpJVP1s0iwAtw 2024年9月9日,微软(Microsoft)在其博客中宣布,已开始在其开源核心加密库Sy ...

  3. 「CF1101F」Trucks and Cities

    题意描述 有 \(N\) 座城市,第 \(i\) 座坐标为 \(a_i\) ,有 \(M\) 辆卡车,第 \(i\) 辆卡车要从城市 \(s_i\) 前往城市 \(e_i\) ,每单位长度耗油量为 \ ...

  4. 小程序image图片缩小不变形

    使用mode =aspectFill 值 说明 scaleToFill 缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素 图片会变形 aspectFit 缩放模式,保持纵横 ...

  5. git pull报错:Pulling without specifying how to reconcile divergent branches is discouraged.

    一.保存内容如下 二.翻译 三.设置为默认即可:git config pull.rebase false

  6. 反范式设计,冗余用户姓名,修改用户姓名后,业务表同步更新 -- MySQL 存储过程

    反范式设计,冗余用户姓名,通过存储过程进行业务表的同步更新. 所有的表,在创建的时候,都加了创建人.修改人的字段..用户姓名发生变化时,要将所有的表都更新一遍. 创建存储过程 MySQL CREATE ...

  7. 1 前端知识学习-初始Web和Web标准

    0️⃣ 初始Web和Web标准 Web ​ Web(World Wide Web) 即全球广域网.也成为万维网.我们常说的Web端就是网页端. 网页 ​ 网页是构成网站的基本元素.网页主要由文字.图像 ...

  8. python - [12] 脚本一文通

    题记部分 一.文件夹&文件 (1)删除空文件夹 # 删除目录中的空文件夹 import os def move_epty_folders(directory_path): for root, ...

  9. Socket通信-Linux系统中C语言实现TCP/UDP图片和文件传输

    TCP实现 传输控制协议(TCP,Transmission Control Protocol) 是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议.TCP是因特网中的传输层协议, ...

  10. Web前端入门第 10 问:HTML 段落标签( <p> )嵌套段落标签( <p> )的渲染结果会怎样?

    HELLO,这里是大熊学习前端开发的入门笔记. 本系列笔记基于 windows 系统. 曾经有一个神奇的 bug 摆在我面前,为什么套娃一样的 HTML 语法,在段落标签 <p> 身上不生 ...