AQS 简介
AQS 是 AbstractQueuedSynchronizer 的简称
从 jdk 1.5
开始引入了并发包 java.util.concurrent
简称 J.U.C
J.U.C极大的提高了 Java 程序的并发性能 ,AQS 又是 J.U.C 的核心, 因此 J.U.C 是并发类中的重重之重. 它提供了一个基于 FIFO 队列 . 这个队列可以用来构建锁 或者其他相关的同步装置的基础框架 . 下图是AQS 底层的数据结构
它底层使用的是双向列表 ,是队列的一种实现 , 因此也可以将它当成一种队列 . 其中 Sync queue 是同步列表 ,它是双向列表 , 包括 head ,tail 节点. 其中head 节点主要用来后续的调度 ; Condition queue 是单向链表 , 不是必须的 , 只有当程序中需要Condition 的时候 ,才会存在这个 单向链表 , 并且可能会有多个 Condition queue
AQS的设计
- 使用 NODE 实现FIFO 队列 , 可以用于实现构建锁或者其他相关同步装置的基础框架
- 使用 int 类型类表示状态
AQS 中 使用了一个status 的成员变量, 基于AQS ,有个同步组件 ReentrantLock 在这个组件里面 status 表示获取锁的线程数, eg . status ==0 表示 还没有线程获取锁, status == 1 表示 有线下获取了锁 ,status > 1 表示 存入锁的数量 - 使用方法是继承
AQS的设计是基于模板方法的 , 使用者需要继承这个AQS 并复写其中的方法 - 子类通过继承并实现它的方法管理其状态( acquire 和 release )的 方法操纵状态
- 可以同时实现排它锁和共享锁模式 (独占 共享)
在使用者的角度, AQS 的功能分为两类, 独占功能 和共享功能. 它的所有子类中要么实现并使用了它的独占功能API , 要么使用了共享锁的功能 , 不会同时使用两套API
AQS 具体实现的大致思路
首先 AQS 内部维护了一个 CLH队列来管理锁 , 线程首先会尝试获取锁 , 如果失败, 就将当前线程及等待状态等信息包成一个NODE 节点 加入到 同步队列 (Sync queue)里 , 接着会不断循环尝试获取锁, 它的条件是当前节点为head 的直接后继才会尝试 , 如果失败就会阻塞自己, 知道自己被唤醒,而当持有锁的线程释放锁的时候会唤醒队列中的后继线程 .
AQS 同步组件
这里选择几个比较重要的
-
countDownLatch
它是闭锁 , 通过一个计数来保证线程是否一直需要阻塞
Semaphore
能控制同一时间并发线程的数目CyclicBarrier
和 countDownLatch 类似 都可阻塞进程ReentrantLock
Condition
Future Task
这些组件完了单独写一个手记.