孤舟笔记 并发篇一 面试总问AQS,它到底是个啥?凭什么它是并发编程的灵魂
文章目录一、先说结论AQS 是一把排队管理器二、没有 AQS 的世界每个锁都得自己造轮子三、AQS 的两大核心state 和队列1. state——一把万能计数器2. CLH 队列——抢不到就排队四、AQS 怎么用抢锁和释放就两步独占模式一人用——以 ReentrantLock 为例共享模式多人用——以 CountDownLatch 为例五、独占 vs 共享一张表分清六、回到全貌一图记住七、回答技巧与点评标准回答加分回答面试官点评个人网站你有没有这种感觉ReentrantLock 用得很溜CountDownLatch 也写过可面试官一问AQS是什么脑子就嗡的一下——好像知道又好像说不清楚。更扎心的是AQS 几乎是 Java 并发面试的必考题不会它跟锁相关的题基本全凉。今天咱们就把它掰开了揉碎了讲明白。一、先说结论AQS 是一把排队管理器||| 维度 | 说明 ||||------|------|||| 全称 | AbstractQueuedSynchronizer抽象队列同步器 |||| 干了啥 | 提供一套抢锁—排队—唤醒的通用框架 |||| 核心组成 | 一个 volatile int state 一个 CLH 双向队列 |||| 核心方法 | tryAcquire抢锁、tryRelease释放、tryAcquireShared共享抢、tryReleaseShared共享释放 |||| 两种模式 | 独占模式一人用 共享模式多人用 |||| 典型实现 | ReentrantLock、CountDownLatch、Semaphore、ReentrantReadWriteLock |一句话记住AQS 就像银行的取号排队系统——有人办业务持有锁其他人拿号排队进队列办完叫下一个唤醒。二、没有 AQS 的世界每个锁都得自己造轮子假设你要写一个独占锁得自己操心怎么标记锁被占了抢不到的线程放哪怎么排队释放了叫谁万一中途取消了怎么办你再写一个共享锁比如信号量上面的问题又得重新想一遍。这就好比每开一家银行都得自己设计一套取号系统、排队规则、叫号逻辑——累不累AQS 的做法把这些排队管理的通用逻辑全部封装好你只需要告诉它什么算抢到了、什么算释放了剩下排队、阻塞、唤醒AQS 全包。三、AQS 的两大核心state 和队列1. state——一把万能计数器privatevolatileintstate;就这么一个 int 变量但它是 AQS 的灵魂ReentrantLockstate 0 表示没人锁state 1 表示锁了state 1 表示重入了CountDownLatchstate 表示还剩几个倒计时没完成Semaphorestate 表示还剩几个许可可用同一个 state不同实现赋予不同含义这就是模板方法的威力。2. CLH 队列——抢不到就排队staticfinalclassNode{volatileNodeprev;// 前驱volatileNodenext;// 后继volatileThreadthread;// 排队的线程volatileintwaitStatus;// 等待状态}抢不到锁的线程会被包装成 Node塞进这个双向链表排队。队列的头节点是当前持有锁的线程的占位后面的节点都是等着被唤醒的。排队规则很简单先来后到FIFO。公平锁严格按队列顺序来非公平锁允许插队——新来的先抢一次抢不到再去排队。四、AQS 怎么用抢锁和释放就两步AQS 采用模板方法模式排队的通用逻辑它写好了你只需要实现抢锁和释放的判断逻辑。独占模式一人用——以 ReentrantLock 为例// 抢锁你告诉 AQS 什么算抢到了protectedbooleantryAcquire(intarg){// state 从 0 变成 1就算抢到了if(compareAndSetState(0,1)){setExclusiveOwnerThread(Thread.currentThread());returntrue;}returnfalse;}// 释放你告诉 AQS 什么算释放了protectedbooleantryRelease(intarg){// state 减到 0就算释放了if(getState()0)thrownewIllegalMonitorStateException();setState(0);setExclusiveOwnerThread(null);returntrue;}抢到了直接用。抢不到AQS 自动把你塞进队列阻塞。释放了AQS 自动叫醒队列里下一个。共享模式多人用——以 CountDownLatch 为例// 共享抢state 倒数到 0所有人都能通过protectedinttryAcquireShared(intarg){returngetState()0?1:-1;// 1抢到-1排队}// 共享释放每次 countDownstate 减 1protectedbooleantryReleaseShared(intarg){for(;;){intcgetState();intnextcc-1;if(compareAndSetState(c,nextc))returnnextc0;// 减到 0 返回 true唤醒所有人}}五、独占 vs 共享一张表分清||| 维度 | 独占模式 | 共享模式 ||||------|---------|---------|||| 同时持有者 | 1个线程 | 多个线程 |||| 抢锁方法 | tryAcquire | tryAcquireShared |||| 释放方法 | tryRelease | tryReleaseShared |||| 典型实现 | ReentrantLock | CountDownLatch、Semaphore |||| 生活类比 | 厕所一人用 | 游乐园多人同时进 |六、回到全貌一图记住AQS 核心架构 ├── statevolatile int—— 不同实现赋予不同含义 └── CLH 双向队列 —— 抢不到锁的线程排队等着 两种模式 ├── 独占模式tryAcquire / tryRelease —— 一人用 └── 共享模式tryAcquireShared / tryReleaseShared —— 多人用 工作流程 抢锁 → 成功直接用 : 进队列阻塞 释放 → 唤醒队列中下一个等待者 核心设计 ├── 模板方法模式排队逻辑 AQS 包了你只写抢/释放 ├── CAS volatile保证 state 操作的原子性和可见性 └── CLH 队列FIFO 公平排队基于前驱节点状态自旋阻塞 口诀AQS 是排队机state 是灵魂 抢锁释放你来定排队唤醒它包完。七、回答技巧与点评标准回答AQS 全称 AbstractQueuedSynchronizer是 Java 并发包中用于构建锁和同步器的框架。它的核心是一个 volatile int state 和一个 CLH 双向队列。state 由子类赋予不同含义如 ReentrantLock 用它表示重入次数CountDownLatch 用它表示剩余计数CLH 队列用于管理抢不到锁的线程的排队和唤醒。AQS 采用模板方法模式子类只需实现 tryAcquire/tryRelease独占或 tryAcquireShared/tryReleaseShared共享排队和唤醒逻辑由 AQS 完成。加分回答提到设计模式AQS 是模板方法模式的经典应用——骨架逻辑写好钩子方法留给子类这就是开闭原则的体现提到公平性AQS 支持公平和非公平两种策略公平锁严格按队列顺序唤醒非公平锁允许新线程先 CAS 抢一次性能更好但可能饥饿提到可中断与超时AQS 的 acquireInterruptibly 和 tryAcquireNanos 支持响应中断和超时放弃比 synchronized 更灵活面试官点评这道题考的是你对 Java 并发底层原理的理解。只说AQS 是个队列太浅了——能讲清楚 state 的设计意义、CLH 队列的排队机制、独占与共享两种模式的区别才算及格。如果还能提到模板方法模式、公平/非公平的实现差异、CAS 与 volatile 的配合面试官会觉得你对并发不是停留在会用层面而是真懂原理稳加分。原文阅读内容有帮助点赞、收藏、关注三连评论区等你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2568875.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!