AtomicReference
的语义是什么?
如果我这样做:
AtomicReference<CustomObject> ref = new AtomicReference<CustomObject>();
然后我做:
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
会返回 最新版CustomObject
吗?
这与post的assylias答案有关:
答案 0 :(得分:3)
是。
AtomicReference
保证发布。
但是,不能保证不同的线程不会在一个毫秒后设置它。
请注意,如果您没有致电compareAndSet()
,则AtomicReference
并不比volatile
字段更好。
答案 1 :(得分:3)
阅读JavaDoc of java.util.concurrent.atomic
:
get
具有读取volatile
变量的记忆效应。
set
具有编写(分配)volatile
变量的记忆效应。
所以保证是:get()
总是返回传递给set()
的最后一个值。在此期间你做了什么并不重要,你使用什么样的锁等等。修改volatile
变量(你有效地做)确保被读取该值的所有其他线程都可见。
答案 2 :(得分:2)
实际上,您的代码存在竞争条件,可能导致新数据丢失:
ref.get()
并获取旧数据ref.set()
ref.set()
由于someMethod()
总是加载新数据,并且总是希望调用者在加载新数据时等待,所有这些额外的东西都是无用的。只需在整个块周围使用一个简单的同步块(或Lock)并抛弃原子参考。根据链接的帖子,看起来你只想做一次,所以使用初始化标志。
private boolean _initialized;
public synchronized void loadLatestData() {
if(!_initialized) {
// load latest data ...
_initilized = true;
}
}
答案 3 :(得分:1)
原子变量(包括AtomicReference
)与volatile
字段具有相同的属性,因为它们在线程之间建立了先发生关系。如果一个线程 A 将值写入易失性字段(或原子变量)而另一个线程 B 从同一个变量读取,那么您无法保证是否 B 将会或不会看到 A 的更改,但您可以保证