本篇文章紧跟着《并发编程艺术》作者的思路去阅读AQS的整体代码,实现细节。
同步队列Node数据结构
AQS两个主要的成员变量,同步状态和同步队列,同步状态int值没啥说的。同步队列的Node结构还是需要了解一下的
- thread:获取同步状态失败的线程
- prev:前驱节点
- next:后继节点
- nextWaiter?
- waitStatus:
独占式同步状态获取与释放
获取
- 方法:
acquire(int arg)
- 同步状态获取
- 节点构造
- 加入同步队列并自旋等待
主要逻辑描述:自定义的同步器,调用其tryAcquire(int arg)方法,保证安全的获取同步状态。若失败,构造同步节点并加入队列的尾部。之后的acquireQueued(Node node,int arg)。自旋获取同步状态。若获取不到则阻塞节点。阻塞线程的唤醒依靠前驱节点的出队或阻塞线程的中断。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
方法:
addWaiter
和enq
- 快速尝试设置尾节点
- 失败后enq自旋设置
- 方法:
acquireQueued
- 节点需要自旋检查前一个节点是否为首节点
- 是首节点才会继续获取同步状态
释放
- 方法:
release(int arg)
共享式同步状态获取与释放
获取
acquireShared(int arg)
tryAcquireShared(int arg)
若大于0获取成功- 小于0获取失败,调用
doAcquireShared(int arg)
doAcquireShared(int arg)
独占式超时获取同步状态
doAcquireNanos(int arg,long nanosTimeout)
- 可以响应中断
- 超时计算公式:nanosTimeout-=now-lastTime。now是当前、lastTime是上次被唤醒时间