J-A-M-E 2022-07-11 20:40
浏览 12
已结题

ReentrantLock的unlock方法,将head节点状态设置为0的作用是啥?

在java的ReentrantLock 的unlock()->release()->unparkSuccessor()方法中

private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    //................
}

关于compareAndSetWaitStatus这段的作用是什么呢? 我研究了下

假设AB两线程,A线程先执行,准备走unlock时切换到B,B线程第一次执行到lock() ->acquire()->acquireQueued()->shouldParkAfterFailedAcquire()方法时

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        return true;
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

compareAndSetWaitStatus(pred, ws, Node.SIGNAL);当B线程走过到else代码块后,时间片用完此时head节点状态为-1

然后回到A线程执行unlock()->release()->unparkSuccessor()

private void unparkSuccessor(Node node) {

    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

释放了锁,然后将head节点的状态改为了0,然后回到B线程

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            
           //B线程执行完方法后返回到这里
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

那么B线程继续for循环,之后就获取到了锁,并置空了head节点,所以A线程在unlock()中修改的head状态并没有什么作用

不是太明白这个步骤,而且注释上写了是允许这个cas失败的,这点也不是太明白

  • 写回答

0条回答 默认 最新

    报告相同问题?

    问题事件

    • 系统已结题 7月19日
    • 创建了问题 7月11日

    悬赏问题

    • ¥30 STM32 INMP441无法读取数据
    • ¥100 求汇川机器人IRCB300控制器和示教器同版本升级固件文件升级包
    • ¥15 用visualstudio2022创建vue项目后无法启动
    • ¥15 x趋于0时tanx-sinx极限可以拆开算吗
    • ¥500 把面具戴到人脸上,请大家贡献智慧
    • ¥15 任意一个散点图自己下载其js脚本文件并做成独立的案例页面,不要作在线的,要离线状态。
    • ¥15 各位 帮我看看如何写代码,打出来的图形要和如下图呈现的一样,急
    • ¥30 c#打开word开启修订并实时显示批注
    • ¥15 如何解决ldsc的这条报错/index error
    • ¥15 VS2022+WDK驱动开发环境