java - 如何在java中最好地实现 "fetch-and-set"?

标签 java multithreading concurrency synchronization atomic

当您关注性能时,在 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/

相关文章:

java - 如何在不使用集合的情况下从数组中删除未使用的元素

java - 为什么 LinkedList 类型不带参数?

.net - 多核环境中的多线程应用程序 - 每个核心的奇怪负载

PHP MySQL并发,数据库中的最大项目数有限

ruby-on-rails - 以线程安全的方式刷新 OAuth 客户端 token

java - 安卓 : Creating Image and filling colors in Canvas

java - Netty Comet 异步请求超时

java - 循环屏障等待方法不起作用

c# - 如何扩展具有 50000 个同时任务的应用程序

java - 线程限制