AQS =》 CountDownLatch

本文深入讲解CountDownLatch的内部实现机制,包括核心类Sync如何继承自AbstractQueuedSynchronizer(AQS)并重写tryAcquireShared方法,以及await和countDown方法的工作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CountDownLatch

核心类:

private final Sync sync;

继承AQS 

AbstractQueuedSynchronizer

核心方法:

await() 阻塞线程   , 直到同步状态status 变成0,线程才会被唤醒或打断抛出打断异常;
countDown()
sync.releaseShared(1); 内部调用releaseShared(1)方法,status减一;

protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}

倒数计时器

CountDownLatch 内部的Sync类, 重新实现了 tryAcquireShared()方法;

AQS的原方法是个空方法,内部直接抛出一个异常;

protected int tryAcquireShared(int arg) {
    throw new UnsupportedOperationException();
}

判断是否阻塞线程

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {

    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
         //如果前继节点的waitStatus值是SIGNAL,即-1, 则 当前线程需要被阻塞;
        return true;
    if (ws > 0) {
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
       // waitStatus > 0 ,即waitStatus 只会是1,CANCELLED,表示已取消,此节点无效了, 通过一个自旋,一直想前找waitStatus 不大于0的节点,并将找到的有效前继节点指向当前线程所在的节点;
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don't park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
       // 此时, waitStatus的值只会是-2或-3,即 CONDITION 或 PROPAGATE, 则通过CAS更新状态值为-1
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

总结下来就是,之前有效前继节点的waitStatus值是SINGAL (-1)时,才会阻塞当前线程;

通过

cancelAcquire()方法,取消继续获取锁;

步骤:

  1.   node.thread = null;     将node内的Thread属性置空;
  2.  跳过无效的前继节点  =》通过自旋,找到有效的前继节点 pred ,即 前继节点的waitStatus 不大于0;
  3. node.waitStatus = Node.CANCELLED;  状态置位1
  4. 记录一下 pred.next , 注意,此时pred.next 并不一定指向node;
  5. tail 尾指针指向 node,即node是尾部节点, 则通过CAS将tail指向其有效前继节点 preNode
  6. compareAndSetNext(pred, predNext, null); 通过CAS比较, pred的后继指向是否仍然是predNext。如果仍然是,则置空,结束;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值