当您关注性能时,在java中实现fetch和set的最佳实践是什么?
假设我有一个排队的尾巴 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)
也要封锁。
基本上,我只想
public void createAndInsertNode(){
Node node = new Node();
node.pred = FetchAndSet(queue.tail,node);
}
第二行是原子的。有什么能允许这样做的吗?
1条答案
按热度按时间yzxexxkh1#
没有必要使用
Unsafe
直接完成这样的任务。避免同步块的一个解决方案是使用原子引用。它最终将使用您打算使用的cas指令。