当您关注性能时,在 Java 中实现获取和设置的最佳实践是什么?
假设我在某处有一个队列尾tail
。
我自己的节点通过用自身替换尾部来将自身排入队列,并将前驱存储在字段 pred
中。
目前我只能想到这样的事情:
public class MyQueue{
public static class Node{public Node pred = null;}
public Node tail = new Node(); //sentinel node
}
然后类似...
import sun.misc.Unsafe;
public class MyClass{
private static long tailOffset = 0;
public MyClass{
//ideally, tailOffset can be hardcoded at compile time s.t. this is obsolete
if(tailOffset <= 0){
this.tailOffset = unsafe.objectFieldOffset(MyQueue.class.getDeclaredField("tail");
}
}
MyQueue queue = new MyQueue();
public void createAndInsertNode(){
Node node = new Node();
synchronized(node){
Node pred = queue.tail;
while(!unsafe.compareAndSwapObject(queue,tailOffset,pred,node)){
pred = queue.tail;
}
node.pred = pred;
}
}
public static final Unsafe unsafe;
static {
try {
Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
unsafeConstructor.setAccessible(true);
unsafe = unsafeConstructor.newInstance();
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) {
throw new RuntimeException(e);
}
}
}
(尚未测试代码,但应该可以传达想法。)
我真的不喜欢在这里使用synchronized
,因为它要求我将对node.pred
的所有访问放入synchronized(node)
block 也是如此。
基本上,我想要的只是
public void createAndInsertNode(){
Node node = new Node();
node.pred = FetchAndSet(queue.tail,node);
}
整个语句第二行是原子的。 有什么可以允许这样做吗?
最佳答案
无需直接使用 Unsafe
来完成此类任务。
避免同步块(synchronized block)的一种解决方案是使用原子引用。它将最终使用与您打算使用的相同的 CAS 指令。
@ThreadSafe
public class MyQueue {
public static class Node {
public Node pred = null;
}
public final AtomicReference<Node> tail = new AtomicReference<>(new Node());
public void insertNewNode() {
Node node = new Node();
node.pred = tail.getAndSet(node);
}
}
关于java - 如何在java中最好地实现 "fetch-and-set"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47038872/