java - AbstractQueuedSynchronizer中CAS的疑惑

 品味a江湖_232_466 发布于 2022-10-26 11:47
  • cas
  • 这段代码是AQS框架中将当前节点入队的操作。

    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }

    上面代码中pred被赋值为尾节点,node为当前节点。我理解的将新节点插入链表尾处的逻辑应当如下:
    node.prev = pred; node节点的前驱指向尾节点
    pred.next = node; 将尾节点的后继设置为当前节点
    tail = node; 将node节点设置为尾节点
    对于上面代码我的疑问如下:
    如果尾节点不为空,node节点的前驱会指向尾节点,然后调用CAS交换pred和node的值。
    此时pred(即tail)的值应该已经是当前节点node的值了,再执行pred.next=node是什么意思呢,这是否存在逻辑问题?

    2 个回答
    • 这个设计是一个双向链表.
      B.prev == A
      A.next == B

      compareAndSetTail 设置成功只是将 tail 更新为当前node. pred.next 是将上一个尾部节点的next设置为当前node这逻辑不存在问题.

      2022-10-27 00:55 回答
    • TZ可能对compareAndSetTail的理解有误。

      private final boolean compareAndSetTail(Node expect, Node update) {
              return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
          }

      在AbstractQueuedSynchronizer的tailOffset位置比较pred的值和期望的node值,如果相同则更新tailOffset位置的值。

      static {
          tailOffset = unsafe.objectFieldOffset
          (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
          ...
      }
      

      compareAndSetTail(pred, node) 这句代码执行完成之后,被修改只是对象AbstractQueuedSynchronizer的tailOffset的值,也就是成员变量tail的值,对于pred的值没有任何影响。至于双向链表,尾部插入,逻辑上没有问题。

      2022-10-27 00:56 回答
    撰写答案
    今天,你开发时遇到什么问题呢?
    立即提问
    热门标签
    PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有