一、核心架构:AQS抽象队列同步器


二、AQS核心机制

1. 三大核心组件:

  • state状态变量:volatile int,表示锁状态(0=未锁定,≥1=锁定/重入次数)

  • CLH队列:双向链表实现的线程等待队列

  • Node节点:封装等待线程和状态(包含:CANCELLED/SIGNAL/CONDITION/PROPAGATE)

2. 关键状态值:

// Node状态常量
static final int CANCELLED =  1;  // 线程已取消
static final int SIGNAL    = -1;  // 后继线程需要唤醒
static final int CONDITION = -2;  // 在条件队列等待
static final int PROPAGATE = -3;  // 共享模式下传播唤醒

三、ReentrantLock工作流程

1. 获取锁(lock()):

2. 释放锁(unlock()):


四、公平锁 vs 非公平锁实现差异

1. 非公平锁(默认)

final boolean nonfairTryAcquire(int acquires) {// 直接尝试获取锁(可能插队)if (c == 0 && compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}// 检查重入else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;setState(nextc);return true;}return false;
}

2. 公平锁

protected final boolean tryAcquire(int acquires) {// 先检查队列是否有等待线程if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}// 重入逻辑相同
}

五、AQS关键方法解析
方法作用
tryAcquire(int)尝试获取锁(需子类实现)
tryRelease(int)尝试释放锁(需子类实现)
acquireQueued()线程加入队列后自旋获取锁
shouldParkAfterFailedAcquire()检查是否应该阻塞线程
unparkSuccessor()唤醒后继节点线程
compareAndSetState()CAS更新state值(保证原子性)

六、问题总结

Q:ReentrantLock如何基于AQS实现?

A:
ReentrantLock的核心实现依赖于AQS框架:

  1. 状态管理

    • 使用AQS的state变量记录锁状态(0=未锁定,≥1=重入次数)

    • 通过compareAndSetState()保证原子更新

  2. 线程排队

    • 获取锁失败的线程被封装为Node加入CLH队列

    • 队列基于双向链表实现(FIFO)

  3. 锁获取流程

    • 先尝试tryAcquire()直接获取锁

    • 失败后调用addWaiter()加入队列尾部

    • 在队列中自旋检查前驱节点状态

    • 最终通过LockSupport.park()阻塞线程

  4. 锁释放流程

    • 调用tryRelease()减少重入计数

    • 当state归零时,调用unparkSuccessor()唤醒队首线程

    • 被唤醒线程重新尝试获取锁

  5. 公平性实现

    • 公平锁:先检查队列是否有等待线程(hasQueuedPredecessors()

    • 非公平锁:允许插队直接尝试获取锁

Q:AQS为什么使用CLH队列?

A:
CLH队列(Craig, Landin, and Hagersten锁)的优势:

  1. 无锁入队:通过CAS操作实现线程安全入队

  2. 低竞争:每个线程只监控前驱节点状态

  3. 高效唤醒:只需修改前驱节点的状态即可唤醒后继线程

  4. 适应性:完美支持超时、中断等复杂场景

Q:ReentrantLock如何基于AQS实现?

A:
ReentrantLock的核心实现依赖于AQS框架,未获取锁的线程会被完全阻塞

  1. 阻塞时机:当线程尝试获取锁失败,且自旋检查后仍无法获取时

  2. 阻塞方式

    • 调用LockSupport.park()方法使线程进入WAITING状态

    • 线程释放CPU资源,不再消耗计算周期

    • 线程状态变为WAITING (parking)

  3. 阻塞位置

    • 线程在CLH队列中排队等待

    • 每个线程监控前驱节点的状态

  4. 唤醒机制

    • 前驱节点释放锁时调用unparkSuccessor()

    • 通过LockSupport.unpark()精确唤醒后继线程

    • 唤醒后线程重新尝试获取锁

  5. 与忙等待的区别

    • 不同于忙等待(while循环),park()会使线程让出CPU

    • 避免空转消耗CPU资源

    • 通过操作系统级同步原语实现高效阻塞/唤醒


七、进阶问题问题
  1. state变量为什么用volatile?

    • 保证多线程间的可见性

    • 确保锁状态变化能被立即感知

    • 配合CAS实现无锁状态更新

  2. 如何处理锁重入?

    // 获取锁时检查当前线程是否是持有者
    if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;setState(nextc); // 增加重入计数return true;
    }
  3. 为什么唤醒后继节点而不是所有线程?

    • 减少不必要的线程唤醒(惊群效应)

    • 保证公平性(FIFO顺序)

    • 提高系统吞吐量

  4. AQS如何支持超时机制?

    public final boolean tryAcquireNanos(int arg, long nanosTimeout) {if (Thread.interrupted()) throw new InterruptedException();return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout); // 超时获取
    }
    • 在自旋过程中检查超时时间

    • 超时后标记节点为CANCELLED

  5. 为什么非公平锁性能更高?

    • 减少线程切换开销(新线程可直接抢锁)

    • 避免唤醒延迟(CLH队列唤醒需要时间)

    • 但可能导致线程饥饿


总结:AQS设计精髓

  1. 模板方法模式:定义骨架流程(acquire/release),子类实现关键操作(tryAcquire/tryRelease)

  2. 无锁算法:通过CAS实现安全的状态更新

  3. 等待队列:优雅管理阻塞线程

  4. 可扩展性:支持独占/共享两种模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/92333.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92333.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/92333.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解程序链接机制:静态链接、ELF加载与动态库实现原理

目录 一、静态链接 1、静态链接的基本概念 1. 静态链接实例分析 2. 目标文件分析 3. 关键观察 4. 重定位机制 5. 注意事项 2、静态链接过程详解 1. 目标文件反汇编分析(上面已分析) 2. 符号表分析 code.o 符号表 hello.o 符号表 3. 链接后的…

python基础复习

复习python基础语法,最好能做到使用python 写一些简单的算法。 1基础基础语法 1.0 输入输出 一个实用的print:format函数print(站点列表 {0}, {1}, 和 {other}。.format(Google, Runoob, other=Taobao)) 站点列表 Google, Runoob, 和 Taobao。print("a", "b…

ZLMediaKit 入门

什么是ZLMediaKit? ZLMediaKit 是一个基于C11的高性能流媒体服务器框架,支持RTSP/RTMP/HLS/HTTP-FLV/WebSocket-FLV等多种流媒体协议。它具有以下特点: 跨平台支持(Linux、Windows、macOS) 高性能,支持高…

接口测试Postman工具高级使用技巧

目录 一、环境与变量的深度应用 多环境动态切换 动态变量与脚本生成 二、Pre-request Script 的妙用 参数签名/加密 接口依赖处理 三、Test Script 的进阶断言 复杂 JSON Schema 校验 数据库断言 四、数据驱动测试 CSV/JSON 文件驱动 动态生成测试用例 环境与变量的…

ZooKeeper学习专栏(四):单机模式部署与基础操作详解

文章目录前言一、单机模式部署架构图部署流程:二、zkCli.sh命令行工具基础操作三、ACL权限控制实践学习资源前言 本文是Zookeeper学习系列的第四篇,将详细讲解Zookeeper的单机模式部署过程以及基础命令行操作,包括节点管理、Watcher机制和AC…

静态登录界面

代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>用户登录</title><st…

Three.js 全景图(Equirectangular Texture)教程:从加载到球面映射

全景图(Equirectangular Texture)是一种特殊的 2D 图像,能通过数学转换模拟 360 环绕视角,常用于创建沉浸式环境(如虚拟全景、天空盒替代方案)。本文将通过完整示例,带你掌握 Three.js 中全景图的加载、映射原理与实际应用。 什么是全景图(Equirectangular Texture)?…

Rocky Linux 9 快速安装 Node.js

Rocky Linux 9 快速安装 Node.js 大家好&#xff0c;我是星哥&#xff01;今天给大家带来 Rocky Linux 9 环境下 Node.js 的安装教程。 本文将详细介绍两种安装方法&#xff0c;帮你快速搭建稳定的 Node.js 环境。 Node.js 是一个非常流行的 JavaScript 运行时环境&#xff…

.NET依赖注入IOC你了解吗?

IOC在Web API 中是经常使用的&#xff0c;但是在一些WPF项目并不是经常使用或者被人熟知的&#xff0c;我把相关依赖注入的内容又做了一次学习和整理什么是依赖注入&#xff1f; 依赖注入是一种设计模式和软件设计原则&#xff0c;用于实现 控制反转。它的核心思想是&#xff1…

Python----大模型(基于Fastapi+streamlit的机器人对话)

一、准备工作 1.1、魔搭社区下载大模型 通义千问2.5-7B-Instruct 模型库 from modelscope.hub.snapshot_download import snapshot_download llm_model_dir snapshot_download(Qwen/Qwen2.5-7B-Instruct,cache_dirmodels) 1.2、启动vllm大模型 python -m vllm.entrypoint…

前端面试专栏-工程化:29.微前端架构设计与实践

&#x1f525; 欢迎来到前端面试通关指南专栏&#xff01;从js精讲到框架到实战&#xff0c;渐进系统化学习&#xff0c;坚持解锁新技能&#xff0c;祝你轻松拿下心仪offer。 前端面试通关指南专栏主页 前端面试专栏规划详情 微前端架构设计与实践 一、微前端核心概念与价值 …

Spring Boot音乐服务器项目-上传音乐模块

项目结构图 相较于上次新增集中在这些地方&#xff1a; &#x1f680; 上传音乐的核心流程 前端投递&#xff1a;用户填写歌手名 选择MP3文件 后端接收&#xff1a;/music/upload 接口化身音乐快递员 安全验证&#xff1a;先查用户是否“持证上岗”&#xff08;登录态&#…

2025年远程桌面软件深度评测:ToDesk、向日葵、TeamViewer全方位对比分析

随着远程办公和数字化协作的深入发展&#xff0c;远程桌面软件已经成为个人用户和企业的必备工具。在2025年的今天&#xff0c;远程控制软件市场呈现出百花齐放的态势&#xff0c;其中ToDesk、向日葵和TeamViewer作为市场上的三大主流选择&#xff0c;各自在技术创新、性能优化…

深度学习-全连接神经网络2

六、反向传播算法 反向传播&#xff08;Back Propagation&#xff0c;简称BP&#xff09;算法是用于训练神经网络的核心算法之一&#xff0c;它通过计算损失函数&#xff08;如均方误差或交叉熵&#xff09;相对于每个权重参数的梯度&#xff0c;来优化神经网络的权重。 1、前…

C语言的历史

C 语言是一种 通用的、过程式的编程语言&#xff0c;由 丹尼斯里奇&#xff08;Dennis Ritchie&#xff09; 在 1972 年于贝尔实验室开发。它以 高效、灵活、贴近硬件 而著称&#xff0c;广泛应用于系统软件、嵌入式系统、驱动程序、游戏引擎、数据库系统等底层开发领域。 C语…

jupyter使用

启动win rcmdjupyter notebook创建python文件

linux 环境服务发生文件句柄泄漏导致服务不可用

问题描述&#xff1a;服务调用远程rest接口 报错&#xff0c;发生too many open files 异常&#xff0c;系统句柄资源耗尽&#xff0c;导致服务不可用。排查经过&#xff1a;1、针对报错代码进行本地构建&#xff0c;构造异常&#xff0c;并进行压测。问题未复现2、经过讨论分析…

手机录制视频时,硬编码和软编码哪个质量高?(硬件编码、软件编码)

文章目录**1. 画质对比**- **软编码**&#xff1a;- **硬编码**&#xff1a;**2. 性能与功耗**- **软编码**&#xff1a;- **硬编码**&#xff1a;**3. 实际应用中的权衡****4. 现代手机的折中方案****5. 如何选择&#xff1f;****总结**在手机录制视频时&#xff0c; 软编码的…

IPv4与IPv6双栈协议:网络过渡的关键技术

为什么需要IPv4与IPv6共存&#xff1f; 在网络技术的世界中&#xff0c;兼容性问题始终是最大的挑战之一。IPv4和IPv6之间存在根本性的不兼容性&#xff0c;这意味着使用不同协议的设备无法直接通信。这种情况就像是两个人试图用完全不同的语言进行对话一样。 目前的网络现状…

【牛客刷题】数字变换

一、题目描述 给出两个数字a,ba,ba,b,aaa每次可以乘上一个大于1的正整数得到新的aa