重读 AbstractQueuedSynchronizer

讲道理,JUC 不只是代码写得好,注释写的也是真的好啊


1. AQS API


AQS 的定位在于实现了一个同步器的框架,能够作为各种同步器的基础。整体来说,这个同步器框架为你提供了一套基础的 API,包括但不限于:

  1. acqure - 独占式的抢占锁
  2. acquireInterruptibly - 独占式抢占且响应中断异常
  3. tryAcquireNanos - 尝试在特定时间内抢占
  4. acquireShared - 共享式抢占(与独占互斥)
  5. release - 释放抢占的独占锁
  6. releaseShared - 释放抢占的共享锁

这些API 可以用来实现各种锁,但在 AQS 的实现来说,它的实现描述了如何控制:

  • 多个线程如何争夺队首来获得同步状态
  • 争夺失败的线程如何排队、阻塞和被唤醒

并且,由于它采用了模板设计模式,任何人可以轻易的扩展 AQS 来实现自定义的同步器和锁。


在看同步接口的实现之前,先看同步队列的结构,以及节点如何入队。

2. CLH lock 队列

AQS 内部维护着一个 FIFO 队列,被称为CLH (Craig,Landin,Hagersten)lock 队列。CLH 队列通常用于提供自旋功能,但在 AQS 中被用于实现一个阻塞的同步器。


     +-------+  prev  +------+        +------+
head |       | <----> | Node | <----> |      |  tail
     +-------+  next  +------+        +------+

队列中的每个 Node 代表一个线程,线程抢夺失败之后通常就会被放进队里排队等待。

2.1 Node

数据结构 Node 是 CLH queue 中的单元类型:

  1. 队列里每个 Node 实例都作为一个特定线程的代表,持有一个等待的线程。
  2. 每个 Node 都包含了一个 waitStatus 字段,这个字段用于跟踪该节点所代表的线程是否应该被阻塞。
  3. 当前 Node 的前驱节点被释放时,当前节点会收到通知。
  4. 每个 Node 可能会多次尝试获取锁,但并不保证成功,如果失败了,就可能需要重新等待。

Node 结构

%E9%87%8D%E8%AF%BB%20AbstractQueuedSynchronizer%20036505e2a0164386a72289a127923ad5/Untitled.png

  • thread: 节点对应的线程
  • prev, next: 前驱节点和后置节点
  • waitStatus: 标记当前节点对应的线程状态
        - SIGNAL:-1, 表示该节点的后继已经被阻塞或者即将被阻塞。因此,当前节点在解锁释放时,需要对后继节点执行 unpark。
        - CONDITION:-2, 表示当前节点在 condition queue 中。
        - PROPAGATE:-3, 下一次共享式同步状态获取将会无条件地传播下去
        - CANCELLED:1, 表示当前节点已经被取消。
        - 0:不是上面的任何一种,是一种默认状态,会在处理的过程中被设置为上面的一种
        - 从值得分布来看,当 waitStatus 值为非负数,则肯定不需要被唤醒,因此在实际使用的很多时候不需要判断具体的值是多少。
        - 所有的修改都通过 CAS 进行。
  • nextWaiter :TODO
// 构造方法
Node() {    // Used to establish initial head or SHARED marker
}

Node(Thread thread, Node mode) {     // Used by addWaiter
    this.nextWaiter = mode;
    this.thread = thread;
}

Node(Thread thread, int waitStatus) { // Used by Condition
    this.waitStatus = waitStatus;
    this.thread = thread;
}

2.2 入队

… 更多,见重读 AbstractQueuedSynchronizer

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值