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

Posted yye0118

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock.unlock()源码解析,部分AQS源码相关的知识,希望对你有一定的参考价值。

我们继续接上篇,本篇是对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源码的主要内容,如果未能解决你的问题,请参考以下文章

Java并发-- ReentrantLock 可重入锁实现原理2 - 释放锁

二探ReentrantLock非公平锁的加解锁过程

二探ReentrantLock非公平锁的加解锁过程

java的锁和zookeeper的锁

[UVA]Pixhawk之姿态解算篇_源码姿态解算算法分析

源码0602-08-掌握-解压缩