java 的锁机制中的AQS原理详解

AQS的全称为(AbstractQueuedSynchronizer),这个类也是在java.util.concurrent.locks下面。这个类似乎很不容易看懂,因为它仅仅是提供了一系列公共的方法,让子类来调用。那么要理解意思,就得从子类下手,反过来看才容易看懂。如下图所示:640?wx_fmt=jpeg

图 5-15 AQS的子类实现

这么多类,我们看那一个?刚刚提到过锁(Lock),我们就从锁开始吧。这里就先以ReentrantLock排它锁为例开始展开讲解如何利用AQS的,然后再简单介绍读写锁的要点(读写锁本身的实现十分复杂,要完全说清楚需要大量的篇幅来说明)。

640?wx_fmt=jpeg

图 5-16 排它锁的构造方法640?wx_fmt=jpeg

图 5-17 排它锁的lock方法

640?wx_fmt=jpeg

妈呀,这代码好费劲,胖哥第一回看也是觉得这样,细心看看也不是想象当中那么难:

○ 首先获取这个锁的状态,如果状态为0,则尝试设置状态为传入的参数(这里就是1),若设置成功就代表自己获取到了锁,返回true了。状态为0设置1的动作在外部就有做过一次,内部再一次做只是提升概率,而且这样的操作相对锁来讲不占开销。

回到图 5-17中对tryAcquire()的调用判定中是通过if(!tryAcquire())作为第1个条件的,如果返回true,则判定就不会成立了,自然后面的acquireQueued动作就不会再执行了,如果发生这样的情况是最理想的。640?wx_fmt=jpeg

看到了tail就应该猜到了AQS是链表吧,没错,而且它还应该有一个head引用来指向链表的头节点,AQS在初始化的时候head、tail都是null,在运行时来回移动。此时,我们最少至少知道AQS是一个基于状态(state)的链表管理方式。

640?wx_fmt=jpeg

图 5-20 enq(Node)的源码

这段代码就是链表的操作,某些同学可能很牛,一下就看懂了,某些同学一扫而过觉得知道大概就可以了,某些同学可能会莫不着头脑。胖哥为了给第三类同学来“开开荤”,简单讲解下这个代码。640?wx_fmt=jpeg

640?wx_fmt=jpeg

图 5-22 AQS被第一个请求成功的线程初始化后

640?wx_fmt=jpeg

图 5-23 插入一个节点步骤前后动作

插入多个节点的时候,就以此类推了哦,总之节点都是在链表尾部写入的,而且是线程安全的。

640?wx_fmt=jpeg

图 5-24 acquireQueued的方法内容

640?wx_fmt=jpeg

640?wx_fmt=jpeg

图 5-26 unlock方法间接调用AQS的release(1)来完成640?wx_fmt=jpeg

图 5-27 tryRelease(1)方法

640?wx_fmt=jpeg

图 5-28 读写锁中的数量计算及限制

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值