如何从一个地址窃取2个MSB进行原子操作?我正在尝试单词CAS
一个例子
public class Node
{
long key;
long value;
Node lchild; // format is flag1,flag2,address
Node rchild; // format is flag1,flag2,address
}
public void createNode()
{
Node n1 = new Node(); //this should create a node with format 0,0,address1
}
public void setFlag1(Node n1)
{
Now the new address should be in format 1,0,address1
}
public void setFlag2(Node n1)
{
Now the new address should be in format 0,1,address1
}
如果我只需要一个额外的标志,可以使用 AtomicReference
。
可以使用AtomicStampedReference
但效率不高,因为它会创建一个包含timeStamp和引用的额外框。
在C中讨论了类似的问题 stealing bits from a pointer
答案 0 :(得分:4)
您可以使用sun.misc.Unsafe
实现此目的除此之外,还有许多compareAndSwap
方法可以处理任何Object中的任意二进制数据。
话虽如此,如果您要实现二叉搜索树,我建议您查看不可变persistent data structures。这些优点包括:
答案 1 :(得分:3)
如果没有实现支持这种操作的JVM,并且正确处理标志位,这是不可能的。在做GC时(此时需要识别所有引用,移动收集器需要更改它们)。即使这样,这也违反了Java的设计原则,它不包括显式解除引用或指针算法(我会计算在引用中更改位并将它们屏蔽以取消引用)。
相反,我建议你创建一个新的复合Edge类型的标志和节点:
public class Node {
long key;
long value;
Child lchild; // child = node reference + flags
Child rchild;
}
// this is the edge type which should also be used to reference the root node with flags
public class Child {
Node child;
BitSet flags;
public Child(Node node) {
this.child = node;
this.flags = new BitSet(2); // we initialize the flags with 00
}
public void setFlag(int index) {
this.flags.set(index); // index would be 0 or 1 here for the two flags
}
public boolean isFlagSet(int index) {
return this.flags.get(index); // index would be 0 or 1 here for the two flags
}
}
答案 2 :(得分:1)
复制Maurice Herlihy和Nir Shavit的书“多处理器编程的艺术”第215页的摘录:
如Pragma 9.8.1中详细描述的,AtomicMarkableReference object包含对类型为T的对象的引用和a 布尔标记。这些字段可以一起原子更新 或单独的。我们将每个节点的下一个字段设为一个 AtomicMarkableReference。线程A逻辑上删除currA 在节点的下一个字段中设置标记位,并共享物理 使用执行add()或remove()的其他线程删除:作为每个 线程遍历列表,它通过物理清理列表 删除(使用compareAndSet())它遇到的任何标记节点。在 换句话说,执行add()和remove()的线程不会遍历 标记节点,他们在继续之前删除它们。包含() 方法与LazyList算法中的方法保持一致,遍历所有方法 节点是否标记,并测试项目是否在 列表基于其键和标记。
答案 3 :(得分:0)
我可以给你使用Java的最佳建议是对数组索引而不是地址进行粗略的处理,因为Java不会公开地址。
答案 4 :(得分:0)
要从对象引用变量可用的位中取出位,需要创建自己的JVM。
首先必须确保实际不使用这些位(例如,当JVM始终在16字节边界上对齐对象时,通过获取引用中的低位)。但是一些JVM使用32位引用的所有位。
接下来,每次加载引用时都必须注入代码,以便在访问关联对象之前清除这些位。
然后你必须为垃圾收集器做同样的事情。
答案 5 :(得分:-1)
你不允许从参考中窃取比特,但有一种解决方法: 您可以使用AtomicStampedReference,它允许您进行比较和交换以原子方式更新引用和整数。您可以使用整数作为状态,或者如果需要,可以从整数的MSB中窃取位。你可以在java中对整数进行位操作,这很酷:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
我最终编写了一个java程序,我从AtomicStampedReference的整数中窃取了2位并将它们用作状态位,我使用整数的剩余30位作为计数器来防止ABA问题。