设为首页 加入收藏

TOP

10分钟从源码级别搞懂AQS(AbstractQueuedSynchronizer)(四)
2023-09-09 10:25:55 】 浏览:151
Tags:10分 钟从源 别搞懂 AQS AbstractQueuedSynchronizer
shouldParkAfterFailedAcquire 获取同步状态失败后应该停放

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    //前驱节点状态
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        //前驱节点状态是SIGNAL 说明前驱释放同步状态回来唤醒 直接返回
        return true;
    if (ws > 0) {
        //如果前驱状态大于0 说明被取消了,就一直往前找,找到没被取消的节点
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        //排在没被取消的节点后面
        pred.next = node;
    } else {
        //前驱没被取消,而且状态不是SIGNAL CAS将状态更新为SIGNAL,释放同步状态要来唤醒
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

实际上是park前的一些准备

再来看看 parkAndCheckInterrupt ,用工具类进入等待状态,被唤醒后检查是否中断

private final boolean parkAndCheckInterrupt() {
        //线程进入等待状态... 
        LockSupport.park(this);
         //检查是否中断 (会清除中断标记位)
        return Thread.interrupted();
}

acquireQueued的中如果未获取同步状态并且抛出异常,最终会执行cancelAcquire取消

当感知到中断时返回true回去,来到第一层acquire方法执行selfInterrupt方法,自己中断线程

acquire流程图:

  1. 先尝试获取同步状态失败则CAS+失败重试添加到AQS末尾
  1. 前驱节点为头节点且获取同步状态成功则返回,否则进入等待状态等待唤醒,唤醒后重试
  1. 在2期间发生异常取消当前节点

image.png

释放同步状态

先进行释放同步状态,成功后头节点状态不为0 唤醒下一个状态不是被取消的节点

public final boolean release(int arg) {
    //释放同步状态
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            //唤醒下一个状态不大于0(大于0就是取消)的节点
            unparkSuccessor(h);
        return true;
    }
    return false;
}

响应中断

acquireInterruptibly用于响应中断的获取同步状态

public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    //查看是否被中断,中断抛出异常
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

doAcquireInterruptibly 与原过程类似,就是在被唤醒后检查到被中断时抛出中断异常

    private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
     &nbs
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 4/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Nacos 注册中心的设计原理:让你.. 下一篇电商类面试问题--01Elasticsearch..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目