Java 并发核心:AQS(AbstractQueuedSynchronizer) 详解

一、什么是 AQS?

AbstractQueuedSynchronizer(简称 AQS)是 Java 并发包 java.util.concurrent.locks 中的一个核心同步框架,用于构建锁和同步器,如:

  • ReentrantLock
  • ReentrantReadWriteLock
  • CountDownLatch
  • Semaphore
  • FutureTask

AQS 通过一个FIFO 双向等待队列(CLH 队列)管理线程的同步状态,使开发者可以专注于同步逻辑,而不必关注线程的调度、阻塞、唤醒等底层细节。


二、AQS 的核心设计

1. 核心成员变量

private volatile int state;       // 同步状态
private transient Node head;      // 队列头节点
private transient Node tail;      // 队列尾节点
  • state:用来表示资源的占用状态(例如是否被锁定、可用信号量数等);
  • headtail:维护一个 CLH 等待队列,用于管理阻塞的线程。

2. 核心方法(模板方法)

AQS 提供一系列模板方法用于子类实现:

// 共享模式
protected int tryAcquireShared(int arg);
protected boolean tryReleaseShared(int arg);// 独占模式
protected boolean tryAcquire(int arg);
protected boolean tryRelease(int arg);

子类需要实现这些方法,以控制对资源的获取与释放逻辑。


三、AQS 工作流程

1. 获取锁(以独占模式为例)

lock.lock() → tryAcquire() 尝试获取 → 获取失败 → 加入 CLH 队列 → park(阻塞)→ 被唤醒时再次尝试

流程:

  1. 调用 tryAcquire() 尝试获取资源;
  2. 如果失败,则将当前线程封装为 Node 加入等待队列;
  3. 阻塞(park)当前线程;
  4. 资源释放后,唤醒下一个等待线程。

2. 释放锁

unlock() → tryRelease() 成功 → 唤醒队列中下一个线程
  • tryRelease()state 设置为 0;
  • 然后调用 unparkSuccessor() 唤醒下一个线程。

四、独占模式 vs 共享模式

模式描述
独占模式同一时刻只能有一个线程访问,如 ReentrantLock
共享模式多个线程可以共享资源,如 Semaphore、CountDownLatch

AQS 区分这两种模式,并分别处理入队、出队、唤醒等逻辑。


五、CLH 队列机制

AQS 使用一种变体的 CLH(Craig–Landin–Hagersten)同步队列 实现线程排队。

队列结构:

head -> Node1 -> Node2 -> ... -> tail
  • 每个节点是一个线程的等待快照;
  • 新线程失败后加入尾部,前驱释放时唤醒后继;
  • 自旋或 park 阻塞等待。

六、典型用法示例

自定义锁的基本写法

class MyLock extends AbstractQueuedSynchronizer {protected boolean tryAcquire(int arg) {return compareAndSetState(0, 1);}protected boolean tryRelease(int arg) {setState(0);return true;}public void lock() {acquire(1); // 内部调用 tryAcquire + 入队逻辑}public void unlock() {release(1);}
}

CountDownLatch 原理

  • 使用共享模式;
  • 每次 countDown() 执行 releaseShared(-1)
  • await() 会在 state = 0 前阻塞。

七、AQS 的优点

优点说明
封装阻塞逻辑使用 LockSupport 封装了 park/unpark
可复用性强模板方法模式,便于自定义同步器
队列高效FIFO 队列实现公平性,性能稳定
支持两种模式支持共享和独占资源控制

八、注意点 & 问题排查

  1. 死锁:一定要在 try...finally 中释放锁;
  2. state 状态:设计时需合理设置 state 的含义(计数、二进制等);
  3. CLH 队列泄露:释放时未正确调用 unpark 会导致阻塞线程永久等待;
  4. 性能瓶颈:高并发下需注意锁竞争,考虑使用 StampedLock 或乐观锁优化。

九、AQS 应用类汇总

类名模式简介
ReentrantLock独占可重入、可中断、公平/非公平
Semaphore共享控制资源访问数目
CountDownLatch共享等待所有任务完成
ReentrantReadWriteLock共享 + 独占高效读写分离
FutureTask独占控制异步任务状态
AbstractQueuedSynchronizer基类框架级同步器

十、总结

  • AQS 是构建 Java 同步工具的核心;
  • 通过队列管理线程阻塞与唤醒;
  • 使用模板方法封装了多种模式;
  • 掌握 AQS = 掌握 Java 并发的核心原理。

补充:AQS 源码流程图解析 + ReentrantLock 实战源码


一、AQS 获取锁(acquire)源码流程

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}

流程图解:

             acquire()│┌───────┴────────┐↓                ↓tryAcquire()     // 自定义尝试获取(成功返回true)     (失败)↓                ↓return      addWaiter(Node.EXCLUSIVE)↓入队列构造双向链表↓acquireQueued(node, arg)↓while(前驱不是head || 不能获取锁)↓        ↓park()   tryAcquire()↓获取成功 → 设置head → unpark下一个

二、AQS 释放锁(release)源码流程

public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;
}

流程图解:

            release()│tryRelease()│是否成功释放?↓   ↑true  false↓获取 head↓唤醒下一个节点(unpark)

三、ReentrantLock 是怎么用 AQS 实现的?

源码结构简图:

public class ReentrantLock implements Lock {abstract static class Sync extends AbstractQueuedSynchronizer {// 核心逻辑都在此子类中}final Sync sync;
}

ReentrantLock 的两个实现版本:

类型类名特点
非公平锁(默认)NonfairSync直接尝试获取锁,抢占式,性能好
公平锁FairSync排队获取,按顺序,不插队,公平但慢一些

tryAcquire 的实现(非公平锁)

protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 尝试直接 CAS 获取锁if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}} else if (current == getExclusiveOwnerThread()) {// 可重入,加重入次数int nextc = c + acquires;setState(nextc);return true;}return false;
}

tryRelease 的实现

protected final boolean tryRelease(int releases) {int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {free = true;setExclusiveOwnerThread(null);}setState(c);return free;
}

四、AQS 线程状态控制核心机制:LockSupport

AQS 底层通过 LockSupport.park()unpark(thread) 来挂起/唤醒线程:

  • park():当前线程阻塞,等待被唤醒;
  • unpark(Thread t):唤醒指定线程;
  • 这种控制机制替代了传统的 wait/notify,更灵活、底层、性能好。

五、总结:如何理解 AQS 的强大之处?

特性说明
模板方法设计只需实现 tryAcquiretryRelease,其他线程队列处理由 AQS 自动完成
双模式支持支持共享与独占两种访问模型
高可复用性可构建多种同步组件(锁、信号量、栅栏等)
高性能结合 CAS、自旋、队列挂起唤醒机制
阻塞线程管理使用 LockSupport 精细控制线程挂起与恢复

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

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

相关文章

LoRA 实战指南:NLP 与 CV 场景的高效微调方法全解析

大模型已成 AI 应用的“标配”,但高昂的训练和部署成本让很多企业望而却步。LoRA(Low-Rank Adaptation)作为一种轻量级微调方案,正成为 NLP 与 CV 场景中低成本定制的利器。本文详细通过详细介绍 LoRA 的核心原理、在文本与图像任…

centos指令

一、python 1、查询运行中脚本 ps aux | grep python2、关闭脚本进程 kill -15 <PID> # 优雅终止&#xff08;SIGTERM&#xff09; kill -9 <PID> # 强制终止&#xff08;SIGKILL&#xff09;

用c语言写一个找两张图片不同处的游戏

回答 思考完成 我们计划开发一个用C语言实现的查找两张图片不同之处的游戏。这个程序需要加载两张图片&#xff0c;然后允许用户通过点击等方式标记出差异的位置。我们将使用一个简单的图形库&#xff08;例如SDL&#xff09;来处理图像和用户交互。步骤&#xff1a;1.加载两…

【深度学习:进阶篇】--4.3.seq2seq与Attention机制

学习目标 目标 掌握seq2seq模型特点掌握集束搜索方式掌握BLEU评估方法掌握Attention机制 应用 应用Keras实现seq2seq对日期格式的翻译 目录 学习目标 1.seq2seq 1.1.定义 1.2.条件语言模型理解 1.3.应用场景 2.注意力机制 2.1.长句子问题 2.2.定义 2.3.公式 3.机器…

MYSQL与PostgreSQL的差异

一、架构设计的根本差异 进程模型 vs 线程模型 ​PostgreSQL​&#xff1a;采用多进程架构&#xff08;每个连接独立进程&#xff09;&#xff0c;通过共享内存通信。优势在于进程隔离性强&#xff0c;单连接崩溃不影响整体服务&#xff0c;但资源消耗较高。 ​MySQL​&…

Wpf布局之StackPanel!

文章目录 前言一、引言二、使用步骤 前言 Wpf布局之StackPanel&#xff01; 一、引言 StackPanel面板在水平或垂直的堆栈中放置元素。这个布局容器通常用于更大、更复杂窗口中的一些区域。 二、使用步骤 StackPanel默认是垂直堆叠 <Grid><StackPanel><Butt…

【MySQL】 内置函数

目录 1.时间函数2.字符串函数3.数学函数4.其他函数 1.时间函数 函数名称描述current_date()当前日期current_time()当前时间current_timestamp()当前时间戳date(datetime)返回datetime参数的日期部分date_add(date,interval d_value_type)在date中添加日期/时间&#xff0c;in…

【RK3568+PG2L50H开发板实验例程】Linux部分/FAN 检测案例

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 1.案例简介 本案例旨在介绍如何测试开发板上风扇接口控制风扇启停与调速功能 2. FAN接口介绍 开发板上 FAN接口是一个…

Spring AI ETL Pipeline使用指南

前言&#xff08;Introduction&#xff09; 版本声明&#xff1a;本文基于 Spring AI 1.0.0 版本编写。由于 Spring AI 目前仍处于活跃开发阶段&#xff0c;API 和组件可能在后续版本中发生变化&#xff0c;请注意及时关注官方文档更新以保持兼容性。 在当今大数据和人工智能快…

Docker 入门教程(九):容器网络与通信机制

文章目录 &#x1f433; Docker 入门教程&#xff08;九&#xff09;&#xff1a;容器网络与通信机制一、Docker 网络模型二、Docker 的四种网络类型三、容器间通信机制四、相关指令 &#x1f433; Docker 入门教程&#xff08;九&#xff09;&#xff1a;容器网络与通信机制 一…

从进攻性安全角度简析 Windows PowerShell

PowerShell 是 Windows 系统中强大的脚本语言和命令行工具&#xff0c;因其灵活性和与 .NET 框架的深度集成&#xff0c;成为攻击者执行恶意操作的热门选择。从进攻性安全视角看&#xff0c;PowerShell 的语言模式、执行策略&#xff08;Execution Policy&#xff09;、AMSI 绕…

MySQL的深度分页如何优化!

MySQL深度分页&#xff08;例如 LIMIT 1000000, 20&#xff09;性能差的主要原因在于 OFFSET 需要扫描并跳过大量数据&#xff0c;即使这些数据最终并不返回。随着 OFFSET 增大&#xff0c;性能会急剧下降。 以下是优化深度分页的常用策略&#xff0c;根据场景选择最适合的方案…

K8s Pod 调度基础——1

目录 一、Replication Controller&ReplicaSet ‌一、Replication Controller (RC)‌ ‌原理‌ ‌特性‌ ‌意义‌ ‌示例与逐行解释‌ ‌二、ReplicaSet (RS)‌ ‌原理‌ ‌特性‌ ‌意义‌ ‌示例与逐行解释‌ ‌三、RC 与 RS 的对比‌ ‌四、总结‌ 二、Dea…

C# Task异步的常用方法

Task异步的常用方法 C# 中的 Task 类是 System.Threading.Tasks 命名空间的一部分&#xff0c;用于表示异步操作。 一、Task.Run(Action action): 此静态方法用于在后台运行一个新任务&#xff0c;并返回与该任务关联的 Task 实例。 本质是将任务放入线程池执行&#xff0c;自…

OpenResty实战之PB级物联网数据处理:时序数据库优化实战

某智慧能源平台通过本方案成功处理了日均1.2万亿数据点&#xff0c;存储成本降低70%&#xff0c;查询延迟从分钟级优化到亚秒级。本文将深入解析PB级物联网数据处理的核心挑战与时序数据库深度优化技巧。 一、物联网数据特性与存储挑战 1.1 物联网数据核心特征 #mermaid-svg-U…

聊聊架构(5)数字化时代的平台商业架构

在数字化浪潮的推动下&#xff0c;平台经济已成为全球经济增长的关键驱动力。作为架构师&#xff0c;不仅要精通架构设计的基础方法论&#xff0c;还需具备敏锐的商业洞察力。架构的价值在于服务业务和商业&#xff0c;而业务的发展又促使架构不断演进。本文将深入探讨平台的商…

【数据增强】精细化贴图数据增强

1.任务背景 假设我有100个苹果的照片&#xff0c;我需要把这些照片粘贴到传送带照片上&#xff0c;模拟“传送带苹果检测”场景。 这种贴图的方式更加合理一些&#xff0c;因为yolo之类的mosaic贴图&#xff0c;会把图像弄的非常支离破碎。 现在我需要随机选择几张苹果图像&am…

HTML响应式Web设计

什么是响应式Web设计&#xff1f; RWD指的是响应式Web设计&#xff08;Responsive Web Design)RWD能够以可变尺寸传递网页RWD对于平板和移动设备是必需的 创建一个响应式设计&#xff1a; <!DOCTYPE html> <html lang"en-US"> <head> <styl…

【读代码】百度开源大模型:ERNIE项目解析

一、项目基本介绍 1.1 项目概述 ERNIE(Enhanced Representation through kNowledge IntEgration)是百度基于PaddlePaddle深度学习框架开发的多模态预训练模型体系。最新发布的ERNIE 4.5系列包含10个不同变体,涵盖从300B参数的巨型MoE模型到0.3B的轻量级模型,形成完整的多…

2025年6月:技术探索与生活平衡的协奏曲

> 当代码与晨跑轨迹在初夏的阳光下交织,我找到了程序员生活的黄金分割点 --- ### 一、技术突破:AI驱动的智能工作流优化系统 这个月我成功部署了第三代自动化工作流系统,核心创新在于**动态决策树+实时反馈机制**。系统可自主优化处理路径,错误率下降62%! ```pyth…