Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 原子参考的保证_Java_Multithreading_Concurrency_Java.util.concurrent - Fatal编程技术网

Java 原子参考的保证

Java 原子参考的保证,java,multithreading,concurrency,java.util.concurrent,Java,Multithreading,Concurrency,Java.util.concurrent,原子引用的语义是什么? 如果我这样做: AtomicReference ref=新的AtomicReference() 然后我会: public void someMethod(){ //do something ref.set(loadNewData()); } private final Sempahore updatePermit = new Sempahore(1); private CustomObject loadNewData(){ C

原子引用的语义是什么?
如果我这样做:

AtomicReference ref=新的AtomicReference()

然后我会:

public void someMethod(){  
 //do something  

 ref.set(loadNewData());  

}  

private final Sempahore updatePermit = new Sempahore(1);  

private CustomObject loadNewData(){  
     CustomObject obj = null;  
     if (updatePermit.tryAcquire()) {  
        obj = ...; //do the loading and create Object  
        updatePermit.release();  
    } else {  
        //update already running, wait  
        updatePermit.acquire();  
        //release the permit immediately  
        updatePermit.release();  
        obj = ref.get(); //????
    }  
    return obj;    
}    
是否有保证在线
obj=ref.get();/
get
将返回most最新版本的
CustomObject

这与assylias的回答有关:

是。
AtomicReference
保证发布

但是,不能保证其他线程不会在毫秒后设置它

请注意,如果您没有调用
compareAndSet()
,则
原子引用
并不比
volatile
字段好。

读取:

  • get
    具有读取
    volatile
    变量的记忆效果

  • set
    具有写入(分配)一个
    volatile
    变量的记忆效果


因此,保证是:
get()
始终返回传递给
set()
的最后一个值。同时,您做什么、使用什么类型的锁等都无关紧要。修改
volatile
变量(您有效地这么做)保证所有其他读取该值的线程都可以看到。

实际上,您的代码有一个争用条件,可能会导致新数据丢失:

  • 第一个调用者进入loadNewData并开始加载新数据(具有信号量)
  • 第二个调用方无法获取信号量并在获取时等待
  • 第一个调用方完成加载并释放信号量(但尚未返回新数据)
  • 第二个调用方获取信号量,调用
    ref.get()
    并获取旧数据
  • 第一个调用者返回传递给
    ref.set()的新数据
  • 第二个调用者返回旧数据,在传递到
    ref.set()时覆盖新数据。
  • 由于
    someMethod()
    总是在加载新数据,而您总是希望调用方在加载新数据时等待,所以所有这些额外的东西都是无用的。只需在整个块周围使用一个简单的同步块(或锁),并放弃原子引用。根据链接的帖子,似乎你只想做一次,所以使用初始化标志

    private boolean _initialized;
    
    public synchronized void loadLatestData() {
      if(!_initialized) {
          // load latest data ...
          _initilized = true;
      }
    }
    
    原子变量(包括
    AtomicReference
    )与
    volatile
    字段具有相同的属性,因为它们在线程之间建立了“发生在之前”的关系。如果一个线程A向一个易失性字段(或原子变量)写入一个值,而另一个线程B从同一个变量中读取,那么您不一定能保证B是否会看到A的更改,但您可以保证这一点

    • 如果B看到A写入的值
    • 然后B还将看到A在写入volatile字段之前写入其他字段(volatile和non-volatile)的结果

    如果线程
    A
    执行
    updatePermit.release()是否保证线程
    B
    能够“查看”从线程
    a
    返回的值?也就是说,
    ref
    会在
    B
    释放信号量后尝试执行
    get
    之前更新吗?但是我不需要
    compareAndSet
    @Jim:那么你最好改用
    volatile
    。如果线程
    A
    updatePermit.release()是否保证线程
    B
    能够“查看”从线程
    a
    返回的值?也就是说,
    ref
    是否会在
    B
    释放信号量后尝试执行
    get
    之前更新?@Jim:信号量与此无关,请阅读
    volatile
    变量保证。Somephores和同步只与普通变量相关。那么什么时候人们更喜欢
    AtomicReference
    而不是
    volatile
    ?@Jim:如果你只使用
    get()
    set()
    ,除了可读性之外,没有什么真正的好处
    atomic*
    在使用CAS操作和其他高性能非阻塞方法(如
    incrementAndGet()
    )时非常有用。解决方法是将
    ref.set
    移动到
    loadNewData
    内,然后再释放
    @IanRoberts-是,或者干脆抛开那些废话,使用一个简单的锁。@jtahlborn我不认为一个简单的锁可以解决链接帖子中详细描述的原始问题。不过我同意比赛条件。如果两个线程T1和T2调用
    loadNewData
    ,T1应该加载数据,T2应该等待T1加载数据,并在T1完成加载后退出该方法。@assylias-我从未实际查看过链接的帖子。然而,一个简单的布尔“initialized”标志将解决“仅执行此操作一次”的问题。将更新。@jtahlborn这实际上不是“只做一次”的问题。见我上面的评论(链接帖子中的原始问题不清楚)。