【juc第三章】:AQS机制全解

发布时间:2026/5/29 5:45:33

【juc第三章】:AQS机制全解 你好我是fengxin_rou这是我的个人主页fengxin_rou的主页❄️欢迎查看我的专栏我的专栏《Java后端学习》、《JAVASE基础》、《JUC并发》、《redis》、《JVM虚拟机》、《MYSQL》、《黑马点评》、《rabbitmq》、《JavaWebAI的talis学习系统》、《苍穹外卖》目录前言AQS 是什么核心设计思想AQS 底层结构state 状态、双向阻塞队列AQS 独占模式、共享模式区别独占模式Exclusive共享模式SharedAQS 排队、唤醒线程的流程1、线程 排队抢不到锁 → 进入等待的流程二、线程唤醒释放锁 → 叫醒别人 的流程AQS为什么要用双向链表1. 为了快速找到前驱节点最核心原因2. 为了高效移除取消等待的线程节点3. 为了保证队列不断裂4. 为了精准唤醒下一个线程总结前言前面两篇学习了JUC并发的基础还有他的锁和关键字的知识现在可以来了解一下JUC的底层框架AQSAQS 是什么核心设计思想AQS 全称AbstractQueuedSynchronizer抽象队列同步器是 Java 并发包JUC的底层核心框架也是 ReentrantLock、Semaphore、CountDownLatch 等工具的统一基石。AQS核心思想是如果被请求的共享资源空闲那么就将当前请求资源的线程设置为有效的工作线程将共享资源设置为锁定状态如果共享资源被占用就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的将暂时获取不到锁的线程加入到队列它提供了一些基本的操作如acquire获取资源和release释放资源这些操作会修改state的值并根据state的值来判断线程是否可以获取或释放资源。AQS 的acquire操作通常会先尝试获取资源如果失败线程将被添加到等待队列中并阻塞等待。release操作会释放资源并唤醒等待队列中的线程。AQS 底层结构state 状态、双向阻塞队列使用一个volatile state 变量表示锁状态state 是锁的属性state0表示资源空闲线程可以抢占state≠0表示资源被占用线程无法直接获取。底层维护一个 FIFO 双向链表队列抢不到锁的线程会被封装成节点进入队列排队等待唤醒。采用 CAS 无锁操作修改状态更新 state 时不需要使用 synchronized 加锁而是通过CAS 原子指令实现无锁、安全、高效的更新。AQS 独占模式、共享模式区别独占模式Exclusive一句话只有一个线程能拿到锁其他人必须等。同一时刻只能有一个线程获取资源state被占用后其他线程不能获取state 0才能拿资源线程获取tryAcquire线程释放tryRelease典型实现ReentrantLock、读写锁的写锁用途写操作、修改数据、保证线程安全共享模式Shared多个线程可以同时拿到资源一起执行。同一时刻允许多个线程同时获取资源state代表可用数量只要 0 就能拿线程获取tryAcquireShared线程释放tryReleaseShared典型实现Semaphore、CountDownLatch、读写锁的读锁用途读操作、限流、多线程等待AQS 排队、唤醒线程的流程1、线程 排队抢不到锁 → 进入等待的流程线程来抢锁先去CAS 修改 state修改成功拿到锁直接执行业务代码修改失败锁被别人占用不能拿锁把当前线程封装成一个Node 节点把节点加入双向队列的尾部检查前面的节点是否正常确认安全后调用LockSupport.park()线程进入阻塞挂起不再运行等待唤醒二、线程唤醒释放锁 → 叫醒别人 的流程拿到锁的线程执行完毕调用释放方法把 state 恢复为 0去队列里找到头节点的下一个有效线程调用LockSupport.unpark()唤醒这个线程被唤醒的线程退出阻塞再次去CAS 抢 state抢成功 →成为新的头节点开始执行业务执行完再释放继续唤醒下一个AQS为什么要用双向链表1. 为了快速找到前驱节点最核心原因线程在阻塞前必须检查前面一个节点的状态判断自己是否可以安全挂起。双向链表有prev指针可以直接获取前驱节点。单向链表没有向前的指针无法快速找到前一个节点。所以必须用双向链表才能实现安全阻塞逻辑。2. 为了高效移除取消等待的线程节点如果线程等待超时、或被中断需要从队列中删掉自己。双向链表直接通过prev和next把自己从队列摘除O (1) 效率。单向链表必须从头遍历找到前驱效率极低。高并发下大量线程取消等待双向链表是唯一选择。3. 为了保证队列不断裂高并发入队、出队时单向链表很容易出现指针丢失导致队列断裂。 双向链表有前后双向指针互相兜底即使某一个指针异常队列依然完整。4. 为了精准唤醒下一个线程AQS 唤醒规则是唤醒头节点的下一个节点。双向链表通过next能立刻找到下一个等待线程。单向链表无法快速找到后继唤醒效率低。总结快速找到前驱节点保证线程安全阻塞高效移除取消、中断、超时的节点高并发下防止队列断裂提高稳定性快速找到后继节点实现精准唤醒。

相关新闻