java - AbstractQueuedSynchronizer中CAS的疑惑
巴扎黑
巴扎黑 2017-04-18 10:52:59
0
2
658

这段代码是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)
左手右手慢动作

TZ可能對compareAndSetTail的理解有誤。

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

在AbstractQueuedSynchronizer的tailOffset位置比較pred的值和期望的node值,如果相同則更新tai​​lOffset位置的值。

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

compareAndSetTail(pred, node) 這句程式碼執行完成之後,被修改只是物件AbstractQueuedSynchronizer的tailOffset的值,也就是成員變數tail的值,對於pred的值沒有任何影響。至於雙向鍊錶,尾部插入,邏輯上沒有問題。

PHPzhong

這個設計是一個双向链表.
B.prev == A
A.next == B

compareAndSetTail 设置成功只是将 tail 更新为当前node. pred.next 是将上一个尾部节点的next设置为当前node這邏輯不存在問題.

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!