juc源码解读五(ReentrantLock相关)

本文详细剖析了ReentrantLock的独占锁加锁、释放流程,包括尝试获取锁、快速入队、完整入队、挂起与唤醒逻辑。此外,还介绍了Condition的等待、唤醒方法,以及CountDownLatch、Semaphore的共享锁机制,展示了这些并发工具在实际应用中的关键点和差异。
摘要由CSDN通过智能技术生成

统一概念

为了更好的理解,这里概念的定义进行一下统一;即根据线程状态来定义队列,WAITING和TIMED_WAITING状态下的线程进入的队列称为等待队列,BLOCKED状态下的线程进入的队列称为阻塞队列;其实条件队列和等待队列是一回事,同步队列和阻塞队列是一回事;

ReentrantLock独占锁加锁流程

尝试获取锁tryAcquire

1)公平模式下会先判断队列前边是否有等待的线程,若有,则走快速入队;
2)tryAcquire方法执行此逻辑,若state为0,则cas修改state字段状态由0到1,修改成功则设置exclusiveOwnerThread为当前线程;
3)同一个线程属于重入,state累加

没拿到锁就先执行一次快速入队addWaiter

addWaiter方法返回当前线程包装出来的node
1)tail不为null,则把当前线程包装成node节点以cas方式直接加在tail节点后
2)队列为空或cas加在tail节点失败,则进入enq方法执行完整入队逻辑

队列为空或快速入队失败则走完整入队enq

enq是个自旋方法,只有当入队成功了,才跳出自旋,返回当前节点的前置节点
1)若tail不为null,则cas设置当前节点为tail,不断自旋,直到成功
2)若tail为null,说明队列为空,说明第一个线程正拿着锁,且当前线程 有可能是第一个获取锁失败的线程(当前时刻可能存在一批获取锁失败的线程…),因为当前持锁的线程,它获取锁时,直接tryAcquire成功了,没有向阻塞队列中添加任何node,所以作为后继需要为它补一个节点,设置一个新node,head和tail都指向这个node,补完node之后,当前线程再次自旋不断尝试cas设置tail,直到成功。此时阻塞队列中的节点状态为初始默认值0,即0<——>0<——>0……0<——>0;
我觉得这个地方可能出现不公平竞争,即第一个获取锁失败的线程刚为持有锁的线程补全新节点,准备走cas入队逻辑时,刚好被别人抢先,所以doug lee眼中的公平锁应该指从排好队之后算起吧,入队之后,严格按照这个顺序获取锁,即为公平模式。

入队后可能会挂起当前线程,以及唤醒后相关的逻辑

1)acquireQueued是个自旋方法,结束自旋的条件是当前节点为head.next节点,且尝试获得锁成功。acquireQueued 返回true 表示挂起过程中线程被中断唤醒过,false 表示未被中断过。
2)判断当前节点不是head.next节点,或者是head.next但抢锁失败,则执行shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt()。第一个方法用于删除取消状态节点,修改插入节点的前置节点状态为-1,自己则继续保持默认状态0,自己的状态从0到-1由其后继节点修改,最终阻塞队列中的所有节点状态变为-1<——>-1<——>…<——>0,因为状态为-1的节点才可以唤醒其next节点。这个方法最终都会返回true。节点的初始化状态均为0,取消节点状态为1;
3)在parkAndCheckInterrupt()方法中调用系统函数执行挂起,以及唤醒后返回是否是被中断唤醒,这里调用的是interrupted方法,返回是否被中断唤醒过,且会将中断标志位复位为false,唤醒后再次进入acquireQueued的自旋,重复以上逻辑。带中断的加锁中,方法doAcquireInterruptibly逻辑和不带中断加锁中的acquireQueued方法一样。(所以如果线程曾被中断过,则连续两次调用interrupted方法,第一次会返回true,第二次会返回false);

最后判断是否被中断唤醒

若是,则执行selfInterrupt方法,其中会执行interrupt方法置位当前线程的中断标记位为true(之所以要设置中断为true,是因为在parkAndCheckInterrupt方法中调用过一次interrupted方法,该方法用于检测是否有过中断,并且会复位中断标记位false)。这是不可中断的加锁流程,按照官方给的注释翻译过来应该叫忽略中断,留给业务处理;
可中断的加锁流程是,当被中断唤醒后,不会再次执行acquireQueued的自旋,而是直接抛异常InterruptedException(),进入cancelAcquire方法,该方法改变当前被中断的线程状态为取消状态,不让其参与锁竞争,而是直接唤醒

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

orcharddd_real

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值