码迷,mamicode.com
首页 > 其他好文 > 详细

ReentrantLock.unlock()源码解析,部分AQS源码

时间:2020-07-26 16:04:56      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:不为   技术   bsp   ase   lse   线程   唤醒   stat   false   

我们继续接上篇,本篇是对unlock方法的跟踪解析。

  调用lock.unlock();

  技术图片

 

   进入后发现,还是使用了sync对象的方法,上篇中以及说明了,sync实际上是对于AQS的一种实现,实现一部分AQS提供的抽象方法。

   我们进入release方法看看

  技术图片

 

   我们能看到,进入后,传递的参数是一,这个是加锁的时候传递的参数是一致的,不同的是,这边调用的是tryRelease方法,尝试释放,我们先分解这个流程,然后进入方法尝试释放锁的过程

  1.判断尝试释放锁释放成功,如果返回值为True,则进入下一步。

  2.将头部节点获取出来,将head节点复制一份引用来进行本次的使用。

  3.判断h不为空,并且状态不等于0,代表还有线程来等待当前线程释放锁,进入unparkSuccessor()方法,将head节点传递进去

  4.返回true。

  5.如果尝试释放锁失败了,返回false。

  接下来,我们来看看第一部分的tryRelease()方法

  技术图片

 

  可以看到,我们直接点击的话,AQS是没有给我们提供任何实现的,而是直接抛出了异常,返回上一步,我们使用ctrl+alt在点击方法,看到有四种实现,我们直接点击在ReentrantLock的实现类

  技术图片

 

 

   我们首先还是对这个流程进行一下分解

  1.获取到当前的state方法,因为当前是上锁状态,所以可以直接减去1。

  2.如果当前线程不等于持有锁的线程,例如,在解锁的时候调用了两次unlock,就会发生这个异常。

  3.设置释放标记。

  4.如果state值在减去1后等于0了,代表这个线程,以及完全释放了这把锁,将标记变为true,并且将持有锁的线程置空。

  5.设置state的值,返回释放标记。

  到此,整个流程我们就基本清楚了,释放锁的标记,是将state和持有锁的线程初始化,但是unlock方法到这一步并没有结束,我们在释放了自身持有的锁后,还需要唤醒等待在队列中的线程来争夺这把锁,我们接着进入

  unparkSuccessor方法:

  技术图片

 

   这个方法主要负责的事情,就是head节点的状态,如果小于0,则修改为0的状态,然后将node节点的下一个节点如果不等于空或者以及被取消了的话,就置空,然后从低部节点往顶部节点循环,获取最后一个状态<=0的node,如果node不等于空,就唤醒s节点的线程。

ReentrantLock.unlock()源码解析,部分AQS源码

标签:不为   技术   bsp   ase   lse   线程   唤醒   stat   false   

原文地址:https://www.cnblogs.com/Yye0118/p/13379625.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!