news 2026/4/22 17:09:44

Java高级面试必问:AQS 到底是什么?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java高级面试必问:AQS 到底是什么?

此篇主要针对大家感兴趣的AQS详细说明,欢迎评论区指正!

一、AQS究竟是什么?

AQS(AbstractQueuedSynchronizer)不是一个具体的锁,而是一个构建锁和同步器的框架。你可以把它想象成汽车工厂的"底盘平台":同样的底盘可以造出轿车、SUV、卡车等各种车型。

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

1.问题背景

在AQS出现之前,Java只有synchronized关键字实现同步,但它存在局限:

  • 无法实现公平锁
  • 没有超时等待机制
  • 没有条件变量的精细控制
  • 无法中断一个正在等待的线程

2.AQS的解决方案

AQS提供了一个通用的并发控制框架,让开发者可以:

  • 自定义各种锁策略
  • 实现复杂的同步需求
  • 获得更好的性能

三、AQS的架构和工作原理

核心结构:CLH队列 + 状态变量

关键代码:AQS核心方法

public abstract class AbstractQueuedSynchronizer { private volatile int state; private transient volatile Node head; private transient volatile Node tail; static final class Node { volatile Node prev; volatile Node next; volatile Thread thread; volatile int waitStatus;

AQS 的两种同步模式

独占模式(Exclusive Mode)

  • 特点:同一时刻仅允许一个线程持有资源。
  • 典型应用ReentrantLockCountDownLatch
  • 核心方法
  • acquire(int arg):获取资源(失败则入队阻塞)。
  • release(int arg):释放资源(唤醒后继节点)。

acquire 流程

共享模式(Shared Mode)

  • 特点:允许多个线程同时持有资源(如读锁、信号量)。
  • 典型应用SemaphoreReentrantReadWriteLock的读锁。
  • 核心方法
  • acquireShared(int arg):获取共享资源。
  • releaseShared(int arg):释放共享资源(可能唤醒多个后继)。

releaseShared 的传播性

private void doReleaseShared() { if (h != null && h != tail) { int ws = h.waitStatus; if (ws == Node.SIGNAL) { if (compareAndSetWaitStatus(h, Node.SIGNAL, 0)) unparkSuccessor(h); // 唤醒后继 else if (ws == 0) compareAndSetWaitStatus(h, 0, Node.PROPAGATE); if (h == head) break; // 若head未变则退出

四、实际开发中如何与AQS交互

场景1:使用现成的AQS实现

普通开发不需要直接使用AQS,而是使用基于AQS的工具类:

import java.util.concurrent.locks.ReentrantLock;import java.util.concurrent.CountDownLatch;import java.util.concurrent.Semaphore;public class AQSInPractice { public static void main(String[] args) throws InterruptedException { // 1. ReentrantLock - 可重入锁 ReentrantLock lock = new ReentrantLock(true); // true表示公平锁 System.out.println("锁已获取"); lock.unlock(); // 2. CountDownLatch - 线程协调 CountDownLatch latch = new CountDownLatch(3); for (int i = 0; i < 3; i++) { new Thread(() -> { latch.countDown(); latch.await(); // 等待所有线程完成 System.out.println("所有任务完成"); // 3. Semaphore - 信号量 Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问 semaphore.acquire(); semaphore.release();

场景2:扩展AQS实现自定义同步器

可以继承AQS实现自定义同步需求:

import java.util.concurrent.locks.AbstractQueuedSynchronizer;// 一个简单的"最多允许N个线程访问"的自定义锁public class SimpleLimitLock { private final Sync sync; public SimpleLimitLock(int limit) { sync = new Sync(limit); private static class Sync extends AbstractQueuedSynchronizer { Sync(int limit) { setState(limit); // 初始化状态为允许的最大线程数 protected int tryAcquireShared(int acquires) { int available = getState(); int remaining = available - acquires; // 如果剩余许可不足或CAS成功,返回结果 if (remaining < 0 || compareAndSetState(available, remaining)) { return remaining; protected boolean tryReleaseShared(int releases) { int current = getState(); int next = current + releases; if (compareAndSetState(current, next)) { return true; sync.acquireShared(1); public void unlock() { sync.releaseShared(1);

五、AQS在Java并发体系中的角色

// Java并发编程的层次结构: ┌─────────────────────────────────────────────────┐ │ Java并发应用层 │ │ • 线程池 (ExecutorService) │ │ • 并发集合 (ConcurrentHashMap) │ │ • 异步任务 (CompletableFuture) │ ├─────────────────────────────────────────────────┤ │ AQS工具类层 │ │ • ReentrantLock │ │ • Semaphore │ │ • CountDownLatch │ │ • CyclicBarrier │ ├─────────────────────────────────────────────────┤ │ AQS框架层 │ │ • 状态管理 (state) │ │ • 队列管理 (CLH队列) │ │ • 线程阻塞/唤醒 (LockSupport) │ ├─────────────────────────────────────────────────┤ │ JVM/OS层 │ │ • synchronized监视器锁 │ │ • CAS指令 (Unsafe类) │ │ • 线程调度 (操作系统) │ └─────────────────────────────────────────────────┘

六、AQS的工作流程示例

以ReentrantLock的加锁过程为例:

sync.acquire(1); // 调用AQS的模板方法 abstract static class Sync extends AbstractQueuedSynchronizer { // AQS.acquire()的调用链: // 1. tryAcquire() 尝试获取锁(子类实现) // 2. addWaiter() 创建节点加入队列 // 3. acquireQueued() 在队列中自旋/阻塞 // 4. 如果被中断过,自我中断恢复状态

具体过程可以用图表示:

七、实际开发中的最佳实践

1.选择合适的同步工具

public class SyncToolSelection { void useReentrantLock() { ReentrantLock lock = new ReentrantLock(true); // 公平锁 void useSemaphore() { Semaphore semaphore = new Semaphore(10); // 最多10个线程同时访问 // 适用于数据库连接池、限流场景 void useCountDownLatch() { CountDownLatch latch = new CountDownLatch(5); // 适用于启动阶段等待初始化完成 void useCyclicBarrier() { CyclicBarrier barrier = new CyclicBarrier(4); // 适用于并行计算,等待所有线程到达屏障

2.避免常见陷阱

public class AQSPitfalls { ReentrantLock lock = new ReentrantLock(); if (someCondition) { return; // 这里直接返回,忘记解锁! lock.unlock(); // 必须在finally中释放 void conditionVariableMistake() { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); // 错误:没有在lock保护下调用await // condition.await(); condition.await(); lock.unlock();

八、总结:AQS在并发编程中的角色

  1. 框架提供者:为锁和同步器提供通用实现框架
  2. 基础设施:是Java并发包的基石,如大楼的地基
  3. 性能优化:相比synchronized提供更灵活的优化空间
  4. 功能扩展:支持公平/非公平、可重入、读写分离等高级特性
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 17:09:42

别再只用MSE了!PyTorch中SmoothL1Loss的beta参数调优实战(附代码对比)

突破默认参数&#xff1a;SmoothL1Loss中beta参数的系统调优指南 在目标检测模型的训练过程中&#xff0c;边界框回归的稳定性常常成为影响最终性能的关键因素。许多开发者习惯性地使用PyTorch中SmoothL1Loss的默认参数&#xff08;beta1.0&#xff09;&#xff0c;却忽略了这一…

作者头像 李华
网站建设 2026/4/22 17:09:41

从 SQL 到语义,Java 开发者的 Agent 实战革命——用 LangChain4j + 通义千问 + MySQL 8.0 打造企业级数据分析智能体

从 SQL 到语义,Java 开发者的 Agent 实战革命——用 LangChain4j + 通义千问 + MySQL 8.0 打造企业级数据分析智能体 一、为什么这不是一篇“Hello Agent”文章 过去两年,很多团队都做过类似的尝试: 给大模型接一个数据库,让它回答“上个月华东区销售额是多少” 给大模型接…

作者头像 李华
网站建设 2026/4/22 17:09:40

别再暴力循环挂钩了!深入剖析极域键盘锁原理与一个钩子的优雅解法(附WH_KEYBOARD_LL钩子实战)

极域键盘锁破解误区与高效解决方案&#xff1a;WH_KEYBOARD_LL钩子的艺术 在Windows系统安全与反控制领域&#xff0c;极域电子教室的键盘锁定机制一直是个热门话题。许多开发者尝试通过各种方法破解这一限制&#xff0c;但网络上流传的解决方案往往存在效率低下、资源浪费甚至…

作者头像 李华
网站建设 2026/4/22 17:05:00

大模型风口已至!月薪30K+的AI岗,4个月速成大模型产品经理的蜕变之路

随着大模型技术的迅猛发展&#xff0c;企业对大模型产品经理的需求日益增长。本文提供一份详尽的大模型产品经理学习路线&#xff0c;涵盖计算机科学基础、人工智能与机器学习基础、大模型技术概览、大模型训练与优化、产品管理与商业分析、实战经验积累、持续学习与自我提升等…

作者头像 李华
网站建设 2026/4/22 17:04:05

《搭建专属节点,让QClaw全天候永久在线》

凌晨三点的高铁上,手机突然弹出客户的紧急消息,要求天亮前整理好过去三个月的项目数据并生成对比报表。我指尖划过冰冷的屏幕,心里清楚这根本不是手机能完成的工作,而家里的主力电脑早在我出发前就已经关机了。我试过用远程工具唤醒电脑,但家里的路由器刚好在那个时候进行…

作者头像 李华