java – 没有volatile的懒惰初始化/ memoization
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – 没有volatile的懒惰初始化/ memoization,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3324字,纯文字阅读大概需要5分钟。
内容图文
![java – 没有volatile的懒惰初始化/ memoization](/upload/InfoBanner/zyjiaocheng/797/0f8f067b15e14fd2ba802005d88865f1.jpg)
看起来Java内存模型没有定义本地缓存的“刷新”和“刷新”,相反人们只是为了简单而这样称呼它,但实际上“发生在之前”的关系意味着以某种方式刷新和刷新(如果你可以解释一下,但不是问题的直接部分).
这让我非常困惑,因为关于Java Memory Model in the JLS的部分不是以易于理解的方式编写的.
因此,请您告诉我,我在以下代码中做出的假设是否正确,是否保证正确运行?
它部分基于Double-checked locking维基百科文章中提供的代码,但作者使用了包装类(FinalWrapper),但其原因并不完全明显.也许支持空值?
public class Memoized<T> {
private T value;
private volatile boolean _volatile;
private final Supplier<T> supplier;
public Memoized(Supplier<T> supplier) {
this.supplier = supplier;
}
public T get() {
/* Apparently have to use local variable here, otherwise return might use older value
* see https://jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html
*/
T tempValue = value;
if (tempValue == null) {
// Refresh
if (_volatile);
tempValue = value;
if (tempValue == null) {
// Entering refreshes, or have to use `if (_volatile)` again?
synchronized (this) {
tempValue = value;
if (tempValue == null) {
value = tempValue = supplier.get();
}
/*
* Exit should flush changes
* "Flushing" does not actually exists, maybe have to use
* `_volatile = true` instead to establish happens-before?
*/
}
}
}
return tempValue;
}
}
我还读过构造函数调用可以内联并重新排序,从而导致对未初始化对象的引用(参见this comment on a blog).直接分配供应商的结果是否安全,或者必须分两步完成?
value = tempValue = supplier.get();
两个步骤:
tempValue = supplier.get();
// Reorder barrier, maybe not needed?
if (_volatile);
value = tempValue;
编辑:这个问题的标题有点误导,目标是减少挥发性字段的使用.如果初始化值已经在线程的高速缓存中,则直接访问值而无需再次查看主存储器.
解决方法:
如果你只有几个单身,你可以减少挥发性的使用.注意:您必须为每个单例重复此代码.
enum LazyX {
;
static volatile Supplier<X> xSupplier; // set somewhere before use
static class Holder {
static final X x = xSupplier.get();
}
public static X get() {
return Holder.x;
}
}
如果您了解供应商,这将变得更加简单
enum LazyXpensive {
;
// called only once in a thread safe manner
static final Xpensive x = new Xpensive();
// after class initialisation, this is a non volatile read
public static Xpensive get() {
return x;
}
}
您可以使用Unsafe避免使字段变得不稳定
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.function.Supplier;
public class LazyHolder<T> {
static final Unsafe unsafe = getUnsafe();
static final long valueOffset = getValueOffset();
Supplier<T> supplier;
T value;
public T get() {
T value = this.value;
if (value != null) return value;
return getOrCreate();
}
private T getOrCreate() {
T value;
value = (T) unsafe.getObjectVolatile(this, valueOffset);
if (value != null) return value;
synchronized (this) {
value = this.value;
if (value != null) return value;
this.value = supplier.get();
supplier = null;
return this.value;
}
}
public static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
private static long getValueOffset() {
try {
return unsafe.objectFieldOffset(LazyHolder.class.getDeclaredField("value"));
} catch (NoSuchFieldException e) {
throw new AssertionError(e);
}
}
}
但是,额外查找是微优化.如果您愿意为每个线程执行一次同步命中,则可以完全避免使用volatile.
内容总结
以上是互联网集市为您收集整理的java – 没有volatile的懒惰初始化/ memoization全部内容,希望文章能够帮你解决java – 没有volatile的懒惰初始化/ memoization所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。