ReentrantLock源码分析

Posted codeHorde

tags:

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

首先看看ReentrantLock类结构。

可以看到三个内部类,一个抽象类Sync,一个是NonfairSync,一个是FairSync。ReentrantLock的lock方法也是调用了sync的lock方法。

ReentrantLock源码分析

sync类继承了AbstractQueuedSynchronizer类,后面简称为AQS,这个类也是核心所在。这里先分析FairSync的实现,公平锁分析完了,非公平锁就一个地方不一样。

ReentrantLock源码分析

可以看到子类主要重写了lock和tryAcquire方法。lock是sync的方法,tryAcquire方法是AQS的方法,都是抽象的,由子类去实现。所以自己想实现一个锁就可以继承AQS重写tryAcquire方法。


lock方法灰调用acquire方法,acquire方法由AQS实现。aquire方法中比较重要的是tryAcquire方法获取锁逻辑(由子类实现),acquireQueued()自己实现

先是获取锁,成功直接返回,失败则会创建一个节点加入到队列中去。

ReentrantLock源码分析

下面直接到FairSync的tryAcqure方法

ReentrantLock源码分析

获取当前状态,0代表未加锁,非0代表未加锁。如果为0,先判断队列中是否存在线程等待,没有等待则CAS去获取锁,获取锁成功后设置当前线程占用锁,返回。如果不是0,再判断持有锁的线程是否是当前线程,这里就是判断是否可重入,重入一次状态加1。

当tryAcquire返回false,就会向下面走先调addWaiter()  封装节点。先贴一张节点类图。Node中最重要的就是几个状态

ReentrantLock源码分析

ReentrantLock源码分析

addwaiter方法进来先判断tail节点是不是为空,因为head和tail都是延迟加载的,所以第一次肯定为null,则进入enq方法,如果不为null,则设置当前节点为尾节点。

ReentrantLock源码分析

自旋设置tail节点。第一次进来肯定是null,设置一个空节点初始化为头,再次循环直到设置为tail节点。现在可以看acquireQueued方法了,这个方法返回false,代表没有被打断,否则是被打断了。

ReentrantLock源码分析

获取前驱,判断是不是节点,如果是头节点则获取锁。获取成功设置当前几点为头点,释放之前头节点。如果不是头节点或者获取锁失败,则会执行shouldParkAfterFailedAcquire()去设置前驱节点状态为-1。所以说到这里已经两次去获取锁了,head节点也可以理解为当前获取到锁的节点。

ReentrantLock源码分析

parkAndCheckInterrupt 调用LockSupport.park(this);休眠。等待别人唤醒

ReentrantLock源码分析

现在看解锁tryrelease ,锁状态减1。头节点不为null,且状态不为0,则去唤醒其他线程

ReentrantLock源码分析

设置当前节点状态为0,找到最近一个节点状态小于等于0的解锁

先介绍这么多,这篇主要介绍阻塞队列,后面再介绍条件队列

以上是关于ReentrantLock源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程实战—–“J.U.C”:ReentrantLock之二lock方法分析

ReentrantLock源码分析

ReentrantLock源码分析--jdk1.8

ReentrantLock的实现原理

ReentrantLock源码分析

[源码分析]ReentrantLock & AbstractQueuedSynchronizer