Java 什么是 AQS ?

这是一个非常核心的Java并发编程面试题。我会用一个清晰易懂的方式为你全面解释AQS。

一、AQS 是什么?

AQS 的全称是 AbstractQueuedSynchronizer,即抽象队列同步器

它是 Java 并发包(java.util.concurrent.locks)中一个构建锁和同步器基础框架。你可以把它理解成一个“万能模板”,JDK中的许多重要的并发工具,其内部都是基于AQS来实现的。

核心思想:
AQS使用一个整型的volatile变量(命名为state来表示同步状态(例如,锁被重入了多少次),并通过一个FIFO(先进先出)的线程等待队列,来处理那些未能获取到锁的线程的排队工作。


二、为什么需要 AQS?它解决了什么问题?

在AQS出现之前,如果想要构建一个锁或同步器,通常需要直接使用底层的 synchronized 关键字和 wait()/notify() 方法。这些底层机制存在一些问题:

  1. 难以控制:无法灵活地实现一些复杂的同步策略(比如,公平锁、尝试获取锁、带有超时的获取等)。

  2. 效率问题synchronized 的锁升级过程在早期版本中性能开销较大。

AQS的出现,将构建同步器的通用逻辑(如线程排队、阻塞、唤醒)封装起来,开发者只需要关注一个核心问题:如何管理这个 state 状态变量。这大大简化了锁和同步器的构建。


三、AQS 的核心原理

AQS的核心原理可以概括为三大组件:

1. 状态变量(state
  • 这是一个用 volatile 修饰的 int 变量。

  • 它的值完全由使用者来决定其含义

    • 在 ReentrantLock 中,state=0 表示锁未被任何线程持有,state=1 表示锁被一个线程持有,state>1 表示锁被同一个线程重入了多次。

    • 在 Semaphore 中,state 表示剩余的许可证数量。

    • 在 CountDownLatch 中,state 表示需要倒数的计数。

2. 线程等待队列(CLH队列的变种)
  • 这是一个双向链表,用于存放所有等待获取锁/资源的线程。

  • 当线程尝试获取 state 失败时,当前线程和相关的等待信息会被构造成一个节点(Node) 并加入到队列尾部。

  • 队列的头节点(head)表示当前正持有锁的线程。

3. 获取/释放资源的模板方法

这是AQS作为“模板”的核心体现。它定义了两组核心方法:

  • 获取资源(Acquire):如 acquire(int arg)

    1. 尝试获取资源(由使用者实现)。

    2. 如果成功,则直接返回。

    3. 如果失败,则将线程加入等待队列,并可能阻塞线程。

  • 释放资源(Release):如 release(int arg)

    1. 尝试释放资源(由使用者实现)。

    2. 如果释放后状态允许唤醒后续线程,则唤醒队列中下一个等待的线程。

AQS已经实现了队列的入队、出队、阻塞、唤醒等复杂逻辑,但它把最关键的“如何尝试获取资源”和“如何尝试释放资源”留给了使用者去实现


四、AQS 的关键方法

使用者需要继承 AbstractQueuedSynchronizer 并重写以下方法来实现自定义的同步逻辑:

方法名描述
protected boolean tryAcquire(int arg)独占式尝试获取资源。成功返回true,失败返回false。
protected boolean tryRelease(int arg)独占式尝试释放资源。成功返回true,失败返回false。
protected int tryAcquireShared(int arg)共享式尝试获取资源。负数表示失败;0表示成功,但无剩余资源;正数表示成功,且有剩余资源。
protected boolean tryReleaseShared(int arg)共享式尝试释放资源。
protected boolean isHeldExclusively()当前同步器是否被独占模式占用。

模式说明:

  • 独占模式(Exclusive):同一时刻只有一个线程能成功获取资源,如 ReentrantLock

  • 共享模式(Shared):同一时刻多个线程可以成功获取资源,如 SemaphoreCountDownLatch


五、AQS 的应用实例

为了让你更直观地理解AQS的工作原理,下图展示了以 ReentrantLock 为例,其内部的AQS是如何协作的:

  • ReentrantLock:内部有一个 Sync 类继承自 AQS。state=0 表示锁空闲,state=1 表示锁被占用。tryAcquire 方法通过 CAS(Compare-And-Swap) 操作尝试将 state 从0改为1。

  • Semaphore:内部同样有一个 Sync 类。state 表示可用的许可证数量。acquire() 就是消耗一个许可证(state--),release() 就是增加一个许可证(state++)。

  • CountDownLatchstate 初始化为一个正数(计数)。await() 方法会检查 state 是否为0;countDown() 方法会将 state 减1,当 state 减到0时,唤醒所有等待的线程。

总结

  • AQS是什么? 它是一个构建锁和同步器的基础框架

  • 核心思想? 用一个 state 变量表示状态,一个FIFO队列管理等待线程。

  • 工作模式? 模板方法模式。AQS负责队列管理和线程调度,使用者只需实现 tryAcquiretryRelease 等核心状态控制方法。

  • 为什么重要? 它是Java并发包的基石,理解了AQS,就理解了大部分JUC同步工具类的工作原理。

它是一个相对底层的组件,日常开发中直接使用的机会不多,但却是理解Java并发编程精髓的关键。

分布式微服务企业级系统是一个基于Spring、SpringMVC、MyBatis和Dubbo等技术的分布式敏捷开发系统架构。该系统采用微服务架构和模块化设计,提供整套公共微服务模块,包括集中权限管理(支持单点登录)、内容管理、支付中心、用户管理(支持第三方登录)、微信平台、存储系统、配置中心、日志分析、任务和通知等功能。系统支持服务治理、监控和追踪,确保高可用性和可扩展性,适用于中小型企业的J2EE企业级开发解决方案。 该系统使用Java作为主要编程语言,结合Spring框架实现依赖注入和事务管理,SpringMVC处理Web请求,MyBatis进行数据持久化操作,Dubbo实现分布式服务调用。架构模式包括微服务架构、分布式系统架构和模块化架构,设计模式应用了单例模式、工厂模式和观察者模式,以提高代码复用性和系统稳定性。 应用场景广泛,可用于企业信息化管理、电子商务平台、社交应用开发等领域,帮助开发者快速构建高效、安全的分布式系统。本资源包含完整的源码和详细论文,适合计算机科学或软件工程专业的毕业设计参考,提供实践案例和技术文档,助力学生和开发者深入理解微服务架构和分布式系统实现。 【版权说明】源码来源于网络,遵循原项目开源协议。付费内容为本人原创论文,包含技术分析和实现思路。仅供学习交流使用。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值