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

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.xdnf.cn/news/659305.html

相关文章:

  • Linux `hostname` 命令深度解析与高阶应用指南
  • Linux中的SELinux
  • RPM之(1)基础使用
  • 【2025】嵌入式软考中级部分试题
  • [特殊字符] useTranslations 客户端使用教程(Next.js + next-intl)
  • n8n中文版安装指南,使用Docker部署N8N中文版
  • 深度学习入门6:pytorch卷积神经网络CNN实现手写数字识别准确率99%
  • 深度学习中的卷积和反卷积
  • 北京大学肖臻老师《区块链技术与应用》公开课:01-课程简介
  • 《软件工程》第 11 章 - 结构化软件开发
  • Qt Creator快捷键合集
  • GESP2024年9月认证C++二级( 第三部分编程题(2)小杨的矩阵)
  • LangChain理解
  • Mybatis框架
  • Redis分布式缓存核心架构全解析:持久化、高可用与分片实战
  • UDP协议原理与Java编程实战:无连接通信的奥秘
  • 【Webtrees 手册】第 4 章 - 编辑指南
  • 通用的管理账号设置设计(一)
  • 02. [Python+Golang+PHP]三数之和,多种语言实现最优解demo
  • 华为OD机试真题——分糖果(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
  • Linux 网络配置现代实践:Netplan 与 ifcfg 的全景对比与工程指南20250526
  • 身份证二要素核验:数字经济时代的信任基石
  • React从基础入门到高级实战:React 核心技术 - 表单处理与验证深度指南
  • 关于模型记忆力的实现方式
  • Linux GPIO子系统深度解析:从历史演进到实战应用
  • 使用 Pfam 和 InterProScan 进行蛋白质家族和功能域的分析
  • 第一章:MLOps/LLMOps 导论:原则、生命周期与挑战
  • 激光开卷落料线:技术革新与产业应用综述
  • PCCW Global 与银河航天在港成功完成低轨卫星测试
  • 紫光同创FPGA实现视频采集转USB2.0输出,基于CY7C68013芯片,提供PDS工程源码和技术支持和QT上位机