【问题标题】:Race conditions with java references带有 java 引用的竞争条件
【发布时间】:2010-09-19 12:49:51
【问题描述】:

原子整数、长整数、布尔值等用于对各自类型进行任何原子更新,因为当我们对它们执行任何操作时可能存在竞争条件,例如 ++。但是可能存在这种竞争条件的引用有哪些不同的情况?

最好的问候,
凯沙夫

【问题讨论】:

    标签: java multithreading reference atomicreference


    【解决方案1】:

    AFAIK 引用不受竞争条件的影响,因为 JVM 保证引用更新是原子操作(与更新 long 不同,其中低 4 字节和高 4 字节在两个不同的步骤中更新)。正如 SLaks 所指出的,唯一的关键情况是 compareAndSet,它本质上不是原子的。这很少与原生引用一起使用,但是当需要一次更新两个(或更多)逻辑上相互依赖的变量时,它是 AtomicReference 的一个已知习惯用法。 Java 并发实践,第 15.3.1 节为此发布了一个示例,使用 AtomicReference 在一个原子操作中更新两个变量(存储在一个简单的类中)。

    AtomicReference 存在的主要原因——除了接口的一致性——是可见性安全发布。从这个意义上说,原子变量是“更好的volatile”。

    【讨论】:

      【解决方案2】:

      ++ 这样的操作会受到竞争条件的影响,因为它们涉及多个谨慎的操作(获取、递增、存储)。

      设置引用 (a = b) 是单个操作,因此不受竞争条件的影响。

      对引用类型 (a.someMethod()) 的操作可以做任何他们想做的事情,并且可能会或可能不会受到竞争条件的影响。

      【讨论】:

      • 那我们为什么要有一个AtomicReference类
      • @keshu: compareAndSet 受制于竞争条件,因为它涉及两个操作。
      【解决方案3】:

      出于学习目的,我使用 AtomicReference 编写了一个 ConcurrentLinkQueue。

            package concurrent.AtomicE;
      
            import java.util.concurrent.atomic.AtomicReference;
      
           public class ConcurrentLinkQueue<V> {
             private final AtomicReference<Node> firstNodePointer = new AtomicReference<Node>();
      
         public void fastOffer(final V data){
          final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
          System.out.println(newNode);
          AtomicReference<Node> pointer = firstNodePointer;
          for(;;){
              if(pointer.get() == null){
                  if(pointer.compareAndSet(null,newNode)){
                      return;
                  }
              }
              pointer = pointer.get().getNext();
          }
      }
      
      private static class Node<V>{
          private AtomicReference<Node> next = new AtomicReference<Node>();
          private volatile V data = null;
          private String threadName = "";
      
          Node(V data1,String threadName){
              this.data = data1;
              this.threadName = threadName;
          }
      
          @Override
          public String toString() {
              return  "threadName=" + threadName +
                      ", data=" + data;
          }
      
          private AtomicReference<Node> getNext() {
              return next;
          }
      
          private void setNext(AtomicReference<Node> next) {
              this.next = next;
          }
      
          private V getData() {
              return data;
          }
      
          private void setData(V data) {
              this.data = data;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多