ReentrantLock 公平锁源码 第2篇(lock公平锁和非公平 源码锁)

  本篇文章为你整理了ReentrantLock 公平锁源码 第2篇(lock公平锁和非公平 源码锁)的详细内容,包含有reentrantlock公平锁和非公平锁原理 lock公平锁和非公平 源码锁 reentrantlock公平锁和非公平锁优缺点 synchronize公平锁 ReentrantLock 公平锁源码 第2篇,希望能帮助你了解 ReentrantLock 公平锁源码 第2篇。

  Reentrant 2

  前两篇写完了后我自己研究了下,还有有很多疑惑和问题,这篇就继续以自问自答的方式写

  如果没看过第1篇的可以先看看那个https:///sunankang/p/16458795.html

  

public final void acquire(int arg) {

 

   if (!tryAcquire(arg)

   acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

   selfInterrupt();

  

 

  进入acquireQueued方法

  

final boolean acquireQueued(final Node node, int arg) {

 

   boolean failed = true;

   try {

   //这个属性的作用是啥???

   boolean interrupted = false;

   for (;;) {

   final Node p = node.predecessor();

   if (p == head tryAcquire(arg)) {

   setHead(node);

   p.next = null; // help GC

   failed = false;

   return interrupted;

   if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())

   interrupted = true;

   } finally {

   if (failed)

   cancelAcquire(node);

  

 

  第一个问题

  interrupted这个变量的作用

  

private final boolean parkAndCheckInterrupt() {

 

   LockSupport.park(this);

   return Thread.interrupted();

  

 

  在parkAndCheckInterrupt方法中最后return的是这个线程是否被打断,它的作用是啥?

  先来回顾interrupt(),interrupted() 和isInterrupted()三者区别,长得很像,注意区分

  interrupt()的作用是中断线程,如果被中断的线程处于阻塞状态下,例如调用wait(),join() sleep(),则抛出异常,否则只是设置一个中断标记为true,注意:仅仅是设置中断状态为true,并不会去 "中断" 线程

  interrupted() 获取线程的中断状态并且清空中断状态(将中断状态设置为false)

  isInterrupted() 获取线程的中断状态并不会清除中断状态

  调用 interrupt 会使park方法立即结束,可以理解为唤醒

  继续代码,看这个变量最后到了哪里

  情况1 没有被打断过

  假设线程没有被中断过,那么parkAndCheckInterrupt返回就是false

  

final boolean acquireQueued(final Node node, int arg) {

 

   boolean failed = true;

   try {

   boolean interrupted = false;

   for (;;) {

   final Node p = node.predecessor();

   if (p == head tryAcquire(arg)) {

   setHead(node);

   p.next = null; // help GC

   failed = false;

   return interrupted;

   if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())

   interrupted = true;

   } finally {

   if (failed)

   cancelAcquire(node);

  

 

  那么不进入 if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())这个if,获取到锁后返回false,回到acquire方法

  

public final void acquire(int arg) {

 

   if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

   selfInterrupt();

  

 

  因为false,所以不进入selfInterrupt(),方法结束

  情况2 park或准备park,被唤醒后直接获取到了锁

  先证明一下打断是会唤醒park中的线程的

  我就再重复粘一下代码了,方便看

  

private final boolean parkAndCheckInterrupt() {

 

   LockSupport.park(this);

   return Thread.interrupted();

  

 

  那么返回的就是true,回到上级acquireQueued方法

  

final boolean acquireQueued(final Node node, int arg) {

 

   boolean failed = true;

   try {

   boolean interrupted = false;

   for (;;) {

   final Node p = node.predecessor();

   if (p == head tryAcquire(arg)) {

   setHead(node);

   p.next = null; // help GC

   failed = false;

   return interrupted;

   //返回到这里

   if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())

   interrupted = true;

   } finally {

   if (failed)

   cancelAcquire(node);

  

 

  因为返回true,所以进入if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt()) 将interrupted返回true

  假设循环获取到锁,那么再返回上一级acquire()

  

public final void acquire(int arg) {

 

   if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

   selfInterrupt();

  

 

  那么进入selfInterrupt()

  

static void selfInterrupt() {

 

   Thread.currentThread().interrupt();

  

 

  是不是有点疑惑?我如果没有调用过interrupt() 那ReentrantLock就不做任何操作,我如果调用了,那它再给我调用一次 ???? 还有情况3

  情况3 park或准备park,被唤醒后没有获取到锁

  

final boolean acquireQueued(final Node node, int arg) {

 

   boolean failed = true;

   try {

   boolean interrupted = false;

   for (;;) {

   final Node p = node.predecessor();

   if (p == head tryAcquire(arg)) {

   setHead(node);

   p.next = null; // help GC

   failed = false;

   return interrupted;

   //假设在调用shouldParkAfterFailedAcquire成功后,马上就要调用parkAndCheckInterrupt 时间片用完了

   if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())

   interrupted = true;

   } finally {

   if (failed)

   cancelAcquire(node);

  

 

  那么这个时候interrupted属性就有用了

  首先要知道一点,一个被中断的线程是无法park的,除非清除了中断状态,即设置为将中断状态设置为false, 口说无凭,直接上图

  第二张图还是在park状态,证明了被打断的线程是无法park的,除非将它中断状态设置为false

  那么回到代码中就能知道这个的作用

  

final boolean acquireQueued(final Node node, int arg) {

 

   boolean failed = true;

   try {

   boolean interrupted = false;

   for (;;) {

   final Node p = node.predecessor();

   if (p == head tryAcquire(arg)) {

   setHead(node);

   p.next = null; // help GC

   failed = false;

   return interrupted;

   if (shouldParkAfterFailedAcquire(p, node)

   parkAndCheckInterrupt())

   interrupted = true;

   } finally {

   if (failed)

   cancelAcquire(node);

  

 

  如果线程被打断唤醒,还是在for(;;)中,还是去获取锁,假设没有获取到呢?那么就一直在for循环中嘎嘎跑,因为线程的状态是被中断的,无法再次park了

  

private final boolean parkAndCheckInterrupt() {

 

   LockSupport.park(this);

   return Thread.interrupted();

  

 

  那么现在懂了最后的Thread.interrupted()作用了吗,就是将中断状态设置回false,好让线程没有获取到锁继续park

  那这时候可能就问了:那你ReentrantLock把中断状态给我清空了,我自己如果有需要根据中断状态来判断的代码咋办啊?

  好,咱们从park先被打断来捋一下

  

private final boolean parkAndCheckInterrupt() {

 

   LockSupport.park(this);

   return Thread.interrupted();

  

 

  因为被打断,线程醒来,执行Thread.interrupted()并清空中断状态,返回true

  

final boolean acquireQueued(final Node node, int arg) {

 

   boolean failed = true;

   try {

   boolean interrupted = false;

   for (;;) {

   final Node p = node.predecessor();

   if (p == head tryAcquire(arg)) {

   setHead(node);

   p.next = null; // help GC

   failed = false;

   return interrupted;

   if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())

   //进入这里

   interrupted = true;

   } finally {

   if (failed)

   cancelAcquire(node);

  

 

  因为返回的是true,所以进入if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt())的代码块,将interrupted属性设置为true

  那么for(;;)循环再来一次,如果没有获取到锁.继续park,直到被唤醒,走tryAcquire()获取到为止,那么此时interrupted变量就为true了

  

public final void acquire(int arg) {

 

   if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

   selfInterrupt();

  

 

  那么退出acquireQueued()方法回到acquire()中,因为acquireQueued()返回的是true,所以进入selfInterrupt()

  

static void selfInterrupt() {

 

   Thread.currentThread().interrupt();

  

 

  所以懂了吗?

  以上就是ReentrantLock 公平锁源码 第2篇(lock公平锁和非公平 源码锁)的详细内容,想要了解更多 ReentrantLock 公平锁源码 第2篇的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: