Java高频面试之并发编程-21

hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶

面试官:详细说说AQS

AQS(AbstractQueuedSynchronizer)是 Java 并发包(java.util.concurrent.locks)的核心基础框架,用于构建锁和其他同步器(如 ReentrantLockSemaphoreCountDownLatch 等)。它通过模板方法模式定义了一套多线程访问共享资源的同步机制,开发者只需继承 AQS 并实现特定方法,即可自定义同步器。


AQS 的核心设计思想

AQS 的核心是 “同步状态管理” + “线程排队机制”

  1. 同步状态(state字段)
    通过一个 volatile int state 字段表示共享资源的状态(如锁是否被占用、信号量剩余许可数等)。

    • 开发者需根据同步器的语义定义 state 的用途(例如:ReentrantLockstate 表示重入次数)。
  2. CLH 队列(线程等待队列)
    采用 CLH 变体的双向链表队列,将未获取到资源的线程封装为 Node 节点并排队等待。

    • CLH 队列的每个节点保存了前驱和后继节点的引用,以及线程的状态(如是否被取消)。
  3. 模板方法模式
    AQS 提供通用的排队和阻塞机制,开发者只需实现以下关键方法(需保证线程安全):

    • tryAcquire(int arg):尝试以独占模式获取资源。
    • tryRelease(int arg):尝试释放独占模式的资源。
    • tryAcquireShared(int arg):尝试以共享模式获取资源。
    • tryReleaseShared(int arg):尝试释放共享模式的资源。
    • isHeldExclusively():判断当前线程是否独占资源。

AQS 的内部结构

  1. state 字段

    private volatile int state; // 核心状态变量
    
    • 通过 getState(), setState(), compareAndSetState() 方法原子操作状态。
  2. CLH 队列

    // 队列头尾指针
    private transient volatile Node head;
    private transient volatile Node tail;// Node 节点结构(每个等待线程封装为一个 Node)
    static final class Node {volatile int waitStatus;     // 等待状态(如 CANCELLED、SIGNAL)volatile Node prev;         // 前驱节点volatile Node next;         // 后继节点volatile Thread thread;     // 关联的线程Node nextWaiter;            // 条件队列的下一节点(用于 Condition)
    }
    
  3. 两种模式

    • 独占模式(Exclusive):资源一次只能被一个线程占用(如 ReentrantLock)。
    • 共享模式(Shared):资源可被多个线程共享(如 SemaphoreCountDownLatch)。

AQS 的工作流程

1. 获取资源(以独占模式为例)
  • 步骤

    1. 调用 acquire(int arg) 方法。
    2. 先尝试 tryAcquire(arg)(需开发者实现),若成功则直接返回。
    3. 若失败,将线程封装为 Node 加入 CLH 队列尾部,并通过 acquireQueued() 自旋或阻塞等待。
    4. 在队列中等待的线程会不断检查前驱节点是否为头节点,若是则再次尝试获取资源。
  • 关键代码逻辑

    public final void acquire(int arg) {if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt(); // 恢复中断状态
    }
    
2. 释放资源
  • 步骤

    1. 调用 release(int arg) 方法。
    2. 先尝试 tryRelease(arg)(需开发者实现),若成功则唤醒队列中的后继节点。
  • 关键代码逻辑

    public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h); // 唤醒后继节点的线程return true;}return false;
    }
    
3. 中断与超时
  • AQS 支持可中断的获取资源(acquireInterruptibly())和超时获取(tryAcquireNanos())。
  • 若线程在等待中被中断或超时,会移除对应的节点并抛出 InterruptedException

AQS 的应用场景

  1. ReentrantLock

    • 通过实现 tryAcquiretryRelease 方法,管理锁的重入计数(state 字段记录持有锁的线程和重入次数)。
  2. Semaphore

    • 使用 state 表示剩余许可数,tryAcquireShared 尝试获取许可,tryReleaseShared 释放许可。
  3. CountDownLatch

    • state 初始化为计数器值,await() 调用 acquireSharedcountDown() 调用 releaseShared
  4. ReentrantReadWriteLock

    • state 的高 16 位用于读锁(共享模式),低 16 位用于写锁(独占模式)。

AQS 的设计优势

  1. 灵活性
    开发者只需关注资源状态的管理(state 操作),无需处理线程排队、阻塞与唤醒等底层逻辑。

  2. 高效性

    • CLH 队列的变体设计减少了锁竞争,通过自旋和 CAS 操作提升性能。
    • 双向链表便于处理取消和超时的节点。
  3. 可扩展性
    支持独占和共享模式,且可通过 Condition 实现更复杂的线程通信(如生产者-消费者模型)。


AQS 的关键源码技巧

  1. 自旋 + CAS
    AQS 大量使用 CAS(Unsafe 类)和自旋操作,例如入队时通过 CAS 保证线程安全:

    private Node enq(final Node node) {for (;;) { // 自旋直到成功Node t = tail;if (t == null) { // 队列为空,初始化头节点if (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}
    }
    
  2. 线程阻塞与唤醒
    使用 LockSupport.park()LockSupport.unpark(thread) 控制线程的阻塞与唤醒,避免优先级反转问题。


技术资料大全:https://pan.q删掉汉子uark.cn/s/aa7f2473c65b

总结

AQS 是 Java 并发包的基石,通过统一的框架解决了同步器的核心问题:

  • 状态管理:通过 state 字段灵活表示资源状态。
  • 线程排队:CLH 队列高效管理等待线程。
  • 模板方法:分离通用逻辑与具体实现,降低开发复杂度。

理解 AQS 是掌握 Java 并发编程的关键,但实际开发中建议优先使用 Java 内置的同步器(如 ReentrantLock),而非直接继承 AQS。

在这里插入图片描述

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

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

相关文章

按键状态机

原工程地址:https://github.com/candylife9/state_machine_example 视频:C语言之状态机编程_02_状态机使用案例分析_哔哩哔哩_bilibili 我觉得讲的挺好的。 来自豆包封装的通用接口 头文件 /*** file key_state_machine.h* brief 通用按键状态机接口…

华为OD机试真题——新学校选址(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

欧拉操作系统下安装hadoop集群

背景:欧拉操作系统下安装CDH集群的时候,需要安装python2.7.5,但是本身欧拉系统对python2的支持可能没有那么好,所以考虑搭建原生的hadoop集群。 基础环境如下 组件名称组件版本欧拉VERSION“22.03 (LTS-SP4)”jdkopenjdk versio…

SQL语句的执行流程

文章目录 一、执行流程二、建立连接三、预处理器四、解析器4.1 词法分析4.2 语法分析4.3 语义分析 五、优化器六、执行器七、返回结果 一、执行流程 阶段主要功能关键组件1. 建立连接身份验证、权限检查连接器2. 预处理器缓存检查、SQL预处理查询缓存3. 解析器词法分析、语法分…

TiDB:从快速上手到核心原理与最佳实践

文章目录 引言第一部分:TiDB快速体验与实践指南1. TiDB概述2. TiDB部署方式2.1 本地测试环境部署2.2 生产环境部署2.3 Kubernetes部署2.4 云服务 3. TiDB基本操作3.1 连接TiDB3.2 数据库和表操作3.3 分区表3.4 事务操作 4. 数据迁移到TiDB4.1 从MySQL迁移4.2 使用Ti…

总结:进程和线程的联系和区别

前言:通过学习javaEE初阶中的多线程章节后加上我自己的理解,想来总结一下线程和进程的联系和区别. 一来是能更好地复习知识,二来是为了记录我的学习路程,相信未来的我回首不会忘记这段难忘的经历. 1.进程 先来谈谈进程:进程是操作系统中资源分配的基本单位. 1)进程的执行方…

边缘云的定义、实现与典型应用场景!与传统云计算的区别!

一、什么是边缘云?‌ 边缘云是一种‌分布式云计算架构‌,将计算、存储和网络资源部署在‌靠近数据源或终端用户的网络边缘侧‌(如基站、本地数据中心或终端设备附近),而非传统的集中式云端数据中心。 ‌核心特征‌&…

海康威视摄像头C#开发指南:从SDK对接到安全增强与高并发优化

一、海康威视SDK核心对接流程​​ 1. ​​开发环境准备​​ ​​官方SDK获取​​:从海康开放平台下载最新版SDK(如HCNetSDK.dll、PlayCtrl.dll)。​​依赖项安装​​:确保C运行库(如vcredist_x86.exe)与S…

《软件工程》第 9 章 - 软件详细设计

目录 9.1 详细设计的任务与过程模型 9.2 用例设计 9.2.1 设计用例实现方案 9.2.2 构造设计类图 9.2.3 整合并优化用例实现方案 9.3 子系统设计 9.3.1 确立内部设计元素 9.3.2 导出设计类图 9.4 构件设计 9.5 类设计 9.5.1 精化类间关系 9.5.2 精化属性和操作 9.5.…

spring+tomcat 用户每次发请求,tomcat 站在线程的角度是如何处理用户请求的,spinrg的bean 是共享的吗

对于 springtomcat 用户每次发请求,tomcat 站在线程的角度是如何处理的 比如 bio nio apr 等情况 tomcat 配置文件中 maxThreads 的数量是相对于谁来说的? 以及 spring Controller 中的全局变量:各种bean 对于线程来说是共享的吗? 一、Tomca…

存储引擎系列--LSM不同Compaction策略性能分析对比

本文介绍一下参考论文里的Compaction性能分析部分,作者在RocksDB的基础上做了多种策略的改造,然后提出了benchmarking方法论,关注compaction性能的哪些维度,并对结果进行分析。 一、Standardization of Compaction Strategies 1.1 实验平台的选择 作者选择了RocksDB作为…

leetcode 3559. Number of Ways to Assign Edge Weights II

leetcode 3559. Number of Ways to Assign Edge Weights II 1. 解题思路2. 代码实现 题目链接:3559. Number of Ways to Assign Edge Weights II 1. 解题思路 这一题是题目3558. Number of Ways to Assign Edge Weights I的进阶版本。 对于题目3558来说&#xf…

推理模型 vs 非推理模型:核心区别及优劣势解析

推理能力上的差异 推理模型在推理能力方面表现突出,它们擅长通过生成中间步骤和“思维链”逐步解决复杂问题。这意味着面对数学计算、逻辑推理、多跳推断等任务时,推理模型能够将问题分解为若干子步骤,每一步给出推理结果,最终汇总得到答案。这种逐步推导的方式使得推理模…

OPENEULER搭建私有云存储服务器

一、关闭防火墙和selinux 二、下载相关软件 下载nginx,mariadb、php、nextcloud 下载nextcloud: sudo wget https://download.nextcloud.com/server/releases/nextcloud-30.0.1.zip sudo unzip nextcloud-30.0.1.zip -d /var/www/html/ sudo chown -R…

Docker 与微服务架构:从单体应用到容器化微服务的迁移实践

随着软件系统规模和复杂性的日益增长,传统的单体应用(Monolithic Application)在开发效率、部署灵活性和可伸缩性方面逐渐暴露出局限性。微服务架构(Microservice Architecture)作为一种将大型应用拆分为一系列小型、独立、松耦合服务的模式,正成为现代企业构建弹性、敏捷…

【C#】Invalidate()的使用

Invalidate()的使用 Invalidate() 是 C# 中用于通知控件需要重新绘制的方法。它通常用于 Windows Forms 应用程序中,当想要更新控件的显示内容时使用。调用 Invalidate() 方法后,系统会安排对该控件进行重绘,这将导致后续调用 OnPaint 方法&…

我店模式系统开发打造本地生活生态商圈

在当今快节奏的商业环境中,商家们面临着越来越多的挑战,包括市场竞争加剧、消费者需求多样化以及运营效率的提高等。为了应对这些挑战,越来越多的商家开始寻求信息化解决方案,以提升运营效率和客户体验。我的店模式系统平台应运而…

Linux(Ubuntu)新建文件权限继承问题

当你在一个工作目权限为777的文件下,新建一个文件的时候,就有可能发生,新建的这个文件,权限和其他文件,或者工作目录不一致的问题,我们不可能每次新建一个文件,就要 sudo chmod -R 777 /PATH 所…

Vue3和React中插件化设计思想

Vue 3 和 React 都广泛支持插件化设计思想,但因为它们的架构和理念不同,插件化的实现方式也不尽相同。以下分别详细讲解这两者中如何实现插件化: 🟩 一、Vue 3 中的插件化实现 Vue 3 继承了 Vue 2 的插件机制,同时增强…

Excel 密码忘记了?巧用PassFab for Excel 解密帮您找回数据!

在工作中,你是否遇到过这样的尴尬时刻?打开重要的 Excel 文件,却发现忘记密码,里面的财务报表、客户数据、项目计划瞬间变成 “加密天书”。重新制作耗时耗力,找专业人员解密又担心数据泄露,这个时候&#…