ReentrantLock之Condition源码解析

总结性概述

  1. signalAll:将节点从条件队列中移除,并尾部插入同步队列中
    1.1 unlock时从同步队列中的头部开始解锁
  2. await: 尾部插入条件队列;释放锁;阻塞;
    2.1 await解除阻塞后(unlock或者中断)
    (1)获取锁
    (2)响应中断
    1. 在等待时中断,则抛出中断异常
    2. 在已经解除阻塞后中断,则自己中断自己

源码分析测试代码介绍

在这里插入图片描述

  1. 启动3个线程,分别执行存放、取出、中断操作

  2. 线程2
    在这里插入图片描述
    2.1 首先执行线程2,此时集合breads为空,则执行notEmpty.await();阻塞

  3. 线程1
    在这里插入图片描述
    3.1 因为线程2执行await已经释放了锁,所以线程1可以通过lock.lock();获取锁
    3.2 让集合breads添加元素,通知线程1:notEmpty.signalAll();

  4. 线程3
    在这里插入图片描述
    4.1 线程3的目的是为了测试在await期间线程中断的场景

Contion#await源码分析

在这里插入图片描述

  1. 线程是否中断,是则抛出中断异常

  2. Node node = addConditionWaiter();尾部插入条件队列
    在这里插入图片描述
    2.1 条件队列是个单向链表结构,由nextWaiter属性维护链表结构
    2.2 如果尾部节点:lastWaiter的等待状态:waitStatus不为Node.CONDITION,则清除(暂未写测试代码分析,感觉像是从头开始清除不为CONDITION的节点)
    2.3 新建节点信息(node),插入条件队列

  3. 释放锁:int savedState = fullyRelease(node)
    在这里插入图片描述
    3.1 释放锁的逻辑与ReentrantLock#unlock一样(可参考之前的文章)

  4. 判断节点是否在同步队列中:isOnSyncQueue(node)
    在这里插入图片描述
    4.1 如果节点状态为CONDITION或者前置节点为空,则说明不在同步队列中
    –> 加入同步队列时,会初始化一个头,然后尾部插入
    4.2 同步队列(双向链表)由prev、next维护,那么如果Next不为空,则说明在同步队列中
    4.3 从尾部往前开始同步队列,直到找到该节点,则说明在同步队列,没找到则说明不在
    4.4 如果不在同步队列中则阻塞:LockSupport.park(this); 先跳到signalAll分析
    4.5 检查在等待的过程中,线程是否中断:checkInterruptWhileWaiting(node)
    4.5.1 如果没有被中断,则返回0,再一次判断isOnSyncQueue,返回false
    4.5.2 如果被中断,则
    在这里插入图片描述
    (1) 在条件等待时被中断,则尾部插入同步队列:enq(node),中断模式为THROW_IE
    (2) 在释放锁后被中断,则返回flase,中断模式为REINTERRUPT
    1. while循环从注解描述,为了防止一种瞬时情况(没有深究)
    (3)跳出循环,直接Break
    4.6 从同步队列的头开始获取锁:acquireQueued(node, savedState)
    (1)在获取锁失败后阻塞,这时线程被中断才会返回true
    4.7 如果条件队列中下一个等待节点不为空,则遍历清除已经取消的等待节点
    4.8 响应等待时中断:reportInterruptAfterWait(interruptMode)
    (1)在条件等待时被中断,则抛出中断异常
    (2)在释放锁后被中断,则中断线程(因为之前通过Thread.interrupted()判断复位了中断位)

Condition#signalAll源码分析

在这里插入图片描述

  1. 判断当前是否持有线程:isHeldExclusively,不是则抛出IllegalMonitorStateException异常
  2. 从头开始通知:doSignalAll(first)
    在这里插入图片描述
    2.1 将头节点从条件队列里移除,然后执行transferForSignal(first) 在这里插入图片描述
    (1)CAS操作将节点状态由CONDITION修改为0
    (2)尾部插入同步队列:Node p = enq(node);
    –>返回的插入节点的前置节点 在这里插入图片描述
    (3)前置节点的状态>0或者CAS修改状态为阻塞失败,则解除阻塞:LockSupport.unpark(node.thread);
    –> 调试时没走解除阻塞逻辑,ws=0
    2.2 遍历执行2.1 操作
  3. unlock释放锁(此时回到await分析的4.5)
    3.1 从同步队列中从头开始解除阻塞
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值