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的。

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

Java中的Condition类是Java多线程编程中的一个重要概念,它提供了类似于Object类的wait()、notify()和notifyAll()方法的功能,并且更加灵活和强大。Condition.await()方法Condition中的一个实例方法,用于线程等待某个条件的发生。 当线程调用Condition.await()方法时,它会释放它所持有的锁,并且进入等待状态,直到其他线程调用相同的Condition对象上的signal()方法或signalAll()方法来唤醒它。与Object.wait()方法不同的是,Condition.await()方法可以选择性地等待某个特定条件的发生,而不是简单地等待任意条件的发生。 Condition.await()方法的使用需要与锁配合使用,通常的做法是在获取锁之后调用Condition.await()方法,然后在条件满足时调用Condition.signal()Condition.signalAll()方法来唤醒等待的线程。具体流程如下: 1. 获取锁。 2. 如果条件不满足,调用Condition.await()方法,线程进入等待状态。 3. 如果条件满足,执行相应的操作。 4. 调用Condition.signal()Condition.signalAll()方法,唤醒等待的线程。 5. 释放锁。 需要注意的是,Condition.await()方法可能会出现虚假唤醒的情况,因此在使用时应该总是在循环中调用Condition.await()方法,并在循环中检查条件是否满足。例如: ``` final Lock lock = new ReentrantLock(); final Condition condition = lock.newCondition(); // 线程1 lock.lock(); try { while (!conditionSatisfied) { condition.await(); } // 执行相应的操作 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } // 线程2 lock.lock(); try { conditionSatisfied = true; condition.signal(); } finally { lock.unlock(); } ``` 在这个例子中,线程1在获取锁之后调用Condition.await()方法等待条件满足,线程2在获取锁之后改变条件状态并调用Condition.signal()方法唤醒等待的线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值