面试官:给我什么是AQS?
AQS简介
- AQS(AbstractQueuedSynchronizer)是Java并发工具包中的一个核心类,用于构建锁和其他同步器。
- AOS(AbstractOwnableSynchronizer)是AQS和AQLS的父类,表示持有者与锁之间的关系。
- AQLS(AbstractQueuedLongSynchronizer)是AQS的扩展,使用
long
类型代替int
类型来存储状态,适用于资源数量可能超过int
范围的场景。
AQS的核心思想
- AQS的核心思想是在多线程访问共享资源时,通过一个
volatile
变量state
来标识资源的锁定状态。 - 当资源空闲时,尝试获取资源的线程会被设置为有效工作线程,资源被锁定。
- 未获取到资源的线程会被放入阻塞队列,等待资源释放。
AQS的数据结构
-
state变量:
- 使用
volatile
修饰,展示当前临界资源的获锁情况。 - 提供了获取和修改
state
的方法,这些方法都是final
修饰的,不能被子类重写。
- 使用
-
CLH双向队列:
- CLH锁是一种自旋锁的改进,是一个虚拟的双向队列。
- AQS将每条请求共享资源的线程封装成一个CLH队列锁的一个节点(Node)。
AQS的资源共享模式
-
独占模式(Exclusive):
- 资源是独有的,每次只能一个线程获取,如
ReentrantLock
。 - 线程获取锁后,可以多次重入,每次重入
state
加1,释放时需要释放相同次数。
- 资源是独有的,每次只能一个线程获取,如
-
共享模式(Share):
- 资源可同时被多个线程获取,如
CountDownLatch
。 - 通过
CAS
操作减少state
值,当state
为0时,唤醒等待的线程。
- 资源可同时被多个线程获取,如
AQS的Node节点
- Node节点存储线程的引用、前驱节点、后继节点等信息。
- 节点状态包括:
CANCELLED
:节点已被取消。SIGNAL
:后继节点等待当前节点唤醒。CONDITION
:当前线程阻塞在Condition。PROPAGATE
:共享模式下,前置节点唤醒后面节点后,唤醒操作无条件传播下去。0
:中间状态,当前节点后面的节点已经唤醒,但当前节点线程还没有执行完成。
AQS的获取资源与释放资源
-
获取资源:
- 入口是
acquire(int arg)
方法,arg
是要获取的资源个数。 - 通过
tryAcquire
方法尝试获取锁资源,失败则将线程封装为Node节点,存入等待队列。
- 入口是
-
释放资源:
- 入口是
release(int arg)
方法。 - 通过
tryRelease
方法尝试释放锁资源,成功后唤醒等待的线程。
- 入口是
AQS的实现细节
-
获取资源:
- 使用
acquireQueued
方法从等待队列的head节点开始,循环向后尝试获取资源。 - 获取失败则继续阻塞,头结点若获取资源成功,则将后继结点设置为头结点。
- 使用
-
释放资源:
- 通过
unparkSuccessor
方法唤醒等待的线程。 tryRelease
方法需要子类实现,如在ReentrantLock
中减少state
值。
- 通过
总结
- AQS是一个强大的同步器框架,通过
state
变量和CLH队列实现资源的锁定和解锁。 - 子类需要实现
tryAcquire
和tryRelease
方法来具体控制资源的获取和释放。
原文地址:https://blog.csdn.net/modelsetget/article/details/140734692
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!