Condition中的transferForSignal()方法的不解

本文探讨了在Java的AQS(AbstractQueuedSynchronizer)中,Condition的transferForSignal()方法中为何进行unpark操作。内容涉及在节点从条件队列转移到同步队列过程中,如何处理已取消节点以及这一操作对性能的影响。分析指出,即使不进行此优化,系统也会最终唤醒节点,但提前unpark可以减少不必要的延迟,尤其在高并发场景下,这种优化能显著提高效率。
摘要由CSDN通过智能技术生成
Node p = enq(node);
···
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);// 唤醒节点上的线程
        return true;
···

通过enq放入同步队列了,他自己会慢慢的争抢锁,就像synchronize中的wait,为什么这里要进行一次unpark?

先看下判断条件。
ws>0,说明是1,是CANCELLED状态,!compareAndSetWaitStatus(p, ws, Node.SIGNAL)) 什么时候把前一个节点(enq(node);返回当前节点的前一个节点,也就是原来的tail)赋值为SIGNAL状态失败?就是前一个节点是CANCELLED的时候,好吧这两个好像是一个命题。

接着看为什么这里要进行一次unpakr?

10-12行的迷惑性就来源于此。实际上,就算去掉10-12行也是满足正确性要求的。因为线程T2释放锁后,依然会将从队头开始的第一个非取消节点唤醒,该节点会继续ConditionObject#await()中的工作(稍后回去分析)。10-12行是为了进一步提升性能,针对两种情况:
如果插入node前,AQS内部等待队列的队尾节点就已经被取消,则满足wc > 0
如果插入node后,AQS内部等待队列的队尾节点已经稳定,满足tail.waitStatus == 0,但在执行ws > 0之后!compareAndSetWaitStatus(p, ws, Node.SIGNAL)之前被取消,则CAS也会失败,满足compareAndSetWaitStatus(p, ws, Node.SIGNAL) == false

这两种情况下,提前唤醒node能够在等待锁的同时,预先完成一部分ConditionObject#await()中无需同步的工作。这部分成本不能被轻易忽视,因为条件队列被应用最多的场景是高并发,大量线程累加起来的成本是很可观的。
链接:https://www.jianshu.com/p/a932c184db52

  1. 在从condition队列到同步队列之前,tail节点被取消了
  2. 在从condition队列到同步队列之后,tail节点没被取消,执行完ws > 0 之后,这段时间,被取消了?就通过!compareAndSetWaitStatus(p, ws, Node.SIGNAL)再判断一下
    这个时候偷偷的提前执行一波,就算不提前执行,AQS队列会不断的把取消节点取消掉,最终还是被unpark的。

总的意思就是为了提升性能,没有这里也是合理的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值