AQS抽象队列同步器

1、Java 并发包下很多 API 都是基于 AQS 来实现的加锁和释放锁等功能的。

⽐如说 ReentrantLock、ReentrantReadWriteLock 底层都是基于 AQS 来实现的。

AQS 对象就是实现加锁和释放锁的关键性的核⼼组件。

2、ReentrantLock加锁和释放锁的原理

ReentrantLock lock = new ReentrantLock();
//加锁
lock.lock();
//释放锁
lock.unlock();

 

①.AQS 对象内部有⼀个核⼼的变量叫做 state,是 int 类型的,代表了加锁的状态。 初始状态下,这个 state 的值是 0

②.AQS 内部还有⼀个关键变量,⽤来记录当前加锁的是哪个线程,初始化状态下,这 个变量是 null

③.线程 1 跑过来调⽤ ReentrantLock 的 lock() ⽅法尝试进⾏加锁,这个加锁的过程,直接就是 ⽤ CAS 操作将 state 值从 0 变为 1,⼀旦线程 1 加锁成功了之后,就可以设置当前加锁线程是⾃⼰

④.每次线程 1 可重⼊加锁⼀次,会判断⼀下当前加锁线程就是⾃⼰,那么他⾃⼰就可以可重 ⼊多次加锁,每次加锁就是把 state 的值给累加 1

⑤.线程 2 过来state 的值不是 0 ,所以 CAS 操作将 state 从 0 变为 1 的过程会失败,会将⾃⼰放⼊ AQS 中的⼀个等待队列

⑥.线程 1 在执⾏完⾃⼰的业务逻辑代码之后,就会释放锁!他释放锁的过程⾮常的简单, 就是将 AQS 内的 state 变量的值递减 1,如果 state 值为 0,则彻底释放锁,会将 “加锁线程” 变 量也设置为 null

⑦.接下来,会从等待队列的队头唤醒线程 2 重新尝试加锁。 线程 2 这时还是⽤ CAS 操作将 state 从 0 变为 1,成功之后代表加锁成功,就会将 state 设置为 1。 还要把 “加锁线程” 设置为线程 2 ⾃⼰,同时线程 2 ⾃⼰就从等待队列中出队了。

 

总结:AQS 就是⼀个并发包的基础组件,⽤来实现各种锁,各种同步组件的。它包含 了 state 变量、加锁线程、等待队列等并发中的核⼼组件

3、公平锁与非公平锁

①非公平锁:

 线程 1 刚释放锁,线程 3直接就跑过来抢先加锁了。导致线程 2 加锁失败继续留在等待队列⾥不断的等着,等着线程 3 释放锁之后,再来唤醒⾃⼰。

②公平锁:

 等待队列中,线程 3 会按照公平原则直接进⼊队列尾部进⾏排队。

### 抽象队列同步器 AQS 的原理与实现 #### 1. AQS 的定义与作用 AQS(AbstractQueuedSynchronizer)是 Java 并发包 `java.util.concurrent` 中的一个核心组件,它提供了一种框架化的机制来构建锁和其他同步工具。AQS 使用了一个基于 FIFO 的双向链表队列来管理线程之间的竞争关系,并通过状态变量控制线程的同步行为[^1]。 #### 2. 核心组成部分 ##### (1)状态变量(state) AQS 维护一个名为 `state` 的整型变量,用来表示同步状态。不同的子类可以通过原子操作修改这个变量以反映资源的占有情况。例如,在 ReentrantLock 中,`state` 表示当前锁被持有的次数;而在 Semaphore 中,`state` 则代表剩余信号量的数量[^3]。 ##### (2)CLH 队列 为了高效地处理大量线程的竞争,AQS 内部采用 CLH(Craig, Landin, and Hagersten locks)变体形式的队列结构。当一个线程试图获取锁失败时,会被封装成节点加入到该队列中等待下一次机会。每个节点包含了指向前后相邻节点的指针以及一些标志位用于记录自身的状况[^4]。 #### 3. 主要方法分类 根据职责划分,AQS 定义了一系列模板方法供开发者覆盖实现: - **独占模式 vs 共享模式** - 独占模式意味着同一时刻只有一个线程能成功获得许可执行关键路径上的代码片段。 - 共享模式允许多个线程同时持有相同的权限级别而不违反约束条件。 - **tryAcquire/tryRelease 系列函数** 这些是非公平版本下的尝试性接口,默认情况下不考虑排队顺序直接抢夺资源使用权。如果调用者满足准入资格则返回 true ,否则 false 。对于释放动作而言则是更新内部计数器并将可能唤醒下一个候选者[^2]。 - **acquire/acquireShared 方法族** 正常途径进入临界区的方式分为两类:一是完全遵循既定规则逐级向上申请直至达成目的为止;二是允许一定程度上的投机取巧即所谓的“乐观锁定策略”。 - **release/releaseShared 函数组** 类似于上面提到的内容只不过方向反转过来而已——前者是从拥有权角度出发逐步削减直到彻底放弃掌控权;后者强调集体利益最大化原则之下共同退让部分权益给后来者享用[^2]。 #### 4. 锁定机制详解 以下是有关如何运用 AQS 构建自定义同步原语的一些简单例子: ```java public class MyMutex extends AbstractQueuedSynchronizer { protected boolean tryAcquire(int acquires) { if (compareAndSetState(0, 1)) { // CAS 更新 state 值 setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } protected boolean tryRelease(int releases) { if (getState() == 0) throw new IllegalMonitorStateException(); setState(0); // 清零恢复初始态 setExclusiveOwnerThread(null); // 解绑当前所有者信息 return true; // 返回值决定是否通知后续待命成员 } public void lock() { acquire(1); } public void unlock() { release(1); } } ``` 上述代码展示了怎样借助 AQS 来模拟互斥锁的行为特性。其中重点在于重写两个虚基类提供的纯虚函数分别对应加锁解锁两阶段的操作逻辑[^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值