Java compareAndSet 以原子方式更新 BST 中的引用

Posted

技术标签:

【中文标题】Java compareAndSet 以原子方式更新 BST 中的引用【英文标题】:Java compareAndSet to atomically update references in a BST 【发布时间】:2013-10-30 03:11:48 【问题描述】:

在二叉树中,我试图以原子方式将父节点的左子节点替换为新节点。 在下面的方法中,pnode.left 指向node,我正在尝试更改它 到replaceNode

在第 1 行中,childPtr 指向 pnode.left 在第 2 行中,oldChildPtr 指向 pnode.left 在第 3 行中,childPtr 原子地从指向pnode.left 更改为replaceNode

但是pnode.left 没有改变。我知道这就是java中的工作方式。 但是我该如何修改这段代码,以便将pnode.left 原子地替换为replaceNode

atomicReplaceLeftChild(node,pnode,replaceNode)

    AtomicReference<Node> childPtr = new AtomicReference<Node>(pnode.left);
    Node oldChildPtr = childPtr.get();
    childPtr.compareAndSet(oldChildPtr, replaceNode);

【问题讨论】:

【参考方案1】:

您的问题(以及它同时被javac 标记的事实)表明您来自C 背景。这没有错,但我相信你在 Java 意义上的“原子”概念并不是你想象的那样。 java.util.concurrent 包中的 Atomic* 类使用内部锁定机制来确保它们中的值在另一个线程访问它们之前不能部分完成。仅仅因为您在代码中使用Atomic* 类并不意味着您的代码执行原子操作。

您的三行代码很“奇怪”,似乎并不代表真实的用例。我这样说是因为代码没有任何事情。它创建了一个 AtomicReference 实例,并与引用的值混淆,但它不会改变 pnode 上的任何内容,这就是我认为你正在尝试做的......

因此,在某些时候您需要拥有pnode.left = replaceNode。您可能希望 pnode.left 实际上是一个 AtomicReference 本身,在这种情况下它将是:pnode.left.compareAndSet(oldChildPtr, replaceNode)

在当前状态下,您的代码并没有做任何重要的事情,当然也没有做您描述它应该做的事情。

希望这不会让您灰心......假设您是 Java 新手,我不羡慕您必须从原子和并发开始......有更容易开始的地方。

【讨论】:

感谢您的回复。我知道我的代码没有做任何事情。这就是为什么在我的问题中我说“但是 pnode.left 没有改变”。我可以按照你的建议去做。 pnode.left.compareAndSet(oldChildPtr, replaceNode)。但是pnode.left必须是AtomicReference&lt;Node&gt;而不是Node【参考方案2】:
static final AtomicReferenceFieldUpdater<Node, Node> c0Update = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "c0");
static final AtomicReferenceFieldUpdater<Node, Node> c1Update = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "c1");
static final AtomicReferenceFieldUpdater<Node, Node> c2Update = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "c2");
static final AtomicReferenceFieldUpdater<Node, Node> c3Update = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "c3");
static final AtomicReferenceFieldUpdater<Node, UpdateStep> infoUpdate = AtomicReferenceFieldUpdater.newUpdater(Node.class, UpdateStep.class, "pending");

我使用 CAS 来做

c0Update.compareAndSet(pending.p, pending.l, pending.newChild)

除了手动展开数组元素之外,还有其他简单的方法吗?

【讨论】:

以上是关于Java compareAndSet 以原子方式更新 BST 中的引用的主要内容,如果未能解决你的问题,请参考以下文章

Java并发AtomicIntegerArray类

cocurrent包 原子性数据类型

Java多线程工具包java.util.concurrent---Atomic

java-CAS

Java并发AtomicReferenceArray类

java中的原子操作类AtomicInteger及其实现原理