JAVA AQS源码深度讲解和分析

为方便理解,本文章以非公平锁ReentrantLock()为例作为突破讲解方法lock。

前置知识:JAVA AQS源码分析前置知识-CSDN博客

ReentrantLock的原理

Lock接口的实现类,基本都是通过聚合了一个队列同步器的子类完成线程访问控制的

 从最简单的lock方法开始看看公平和非公平

 公平锁和非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件:hasQueuedPredecessors()-----公平锁加锁时判断等待队列中是否存在有效节点的方法

以非公平锁ReentrantLock()为例作为突破---方法lock()

对比公平锁和非公平锁的tryAcquire()方法的实现代码,其实差异就在于非公平锁获取锁时比公平锁中少了一个判断!hasQueuedPredecessors(),hasQueuedPredecessors()中判断了是否需要排队,导致公平锁和非公平锁的差异如下:

  • 公平锁:公平锁讲究先来后到,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入到等待队列中;
  • 非公平锁:不管是否有等待队列,如果可以获取到锁,则立刻占有锁对象。也就是说队列的第一个排队线程苏醒后,不一定就是排头的这个线程获得锁,它还需要参加竞争锁(存在线程竞争的情况下),后来的线程可能不讲武德插队夺锁了。

源码解读 

1. lock()

  • 非公平锁,先试图直接抢占锁(调用compareAndSetState),若未抢占成功才调用acquire方法。
  • 即:不管是否有等待队列,都先进行锁的抢夺

  • 公平锁,直接调用acquire方法。

2.acquire()

  • 类似一个责任链,先尝试获取锁(tryAcquire),若失败则加入队列(addWriter)并坐稳队列(acquireQueued)
  • return false:继续推进条件,走下一个方法
  • return true:结束

2.1. tryAcquire(arg)

  • 流程:先判断锁状态,若为0(未锁定)则尝试争抢锁,否则判断当前持有锁的是否是当前线程,否则返回fase
  • 对比:公平锁和非公平的的区别是是否进行!hasQueuedPredecessors() 的判断,即是否判断队列中是否有等待的节点。
  • 非公平锁:

  • 公平锁:

2.2.addwaiter

  • 从enq方法中我们可以知道在双向链表中,第一个节点为虚节点(也叫做哨兵节点),其实不存储任何信息,只是占位。真正的第一个有数据的节点,是从第二个节点开始的

  • 假如此时有线程C进入

2.3.acquireQueued(addWeiter(Node.EXCLUSIVE), arg)

3. unlock()

总览:

  • tryRelease

4.其他线程unlock后的同时其他线程的acquireQueued

5. acquireQueued执行失败或取消执行时

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值