Guava:MemoizingSupplier 线程安全
Guava: MemoizingSupplier thread safety
Guava Suppliers-class 包含 MemoizingSupplier:
static class MemoizingSupplier<T> implements Supplier<T>, Serializable {
final Supplier<T> delegate;
transient volatile boolean initialized;
// "value" does not need to be volatile; visibility piggy-backs
// on volatile read of "initialized".
transient T value;
MemoizingSupplier(Supplier<T> delegate) {
this.delegate = delegate;
}
@Override public T get() {
// A 2-field variant of Double Checked Locking.
if (!initialized) {
synchronized (this) {
if (!initialized) {
T t = delegate.get();
value = t;
initialized = true;
return t;
}
}
}
return value;
}
@Override public String toString() {
return "Suppliers.memoize(" + delegate + ")";
}
private static final long serialVersionUID = 0;
}
谁能解释一下这条评论是什么意思?
"value" does not need to be volatile; visibility piggy-backs on volatile read of "initialized".
"initialized" 字段上的 volatile 如何影响 "value" 字段?
根据 this 文章,我们可以得到 "initialized" 和 "value" 字段的不一致组合(例如 true+null)。我错了吗?
这句话基本上意味着 value
的读写以某种方式与易失性读写进行排序,以保证写入的值对读取可见。
(简化)证明
如果这个值没有被初始化,程序会执行那两条语句:
value = t; //normal write
initialized = true; //volatile write
如果值被初始化,程序将执行这两个语句:
if(!initialized) { ... } //volatile read
return value; //normal read
多亏了可变语义,可变写入和可变读取之间存在先行关系,return value
中的正常读取保证可以看到 value = t
处的写入。这是有效的,因为正常写入是 before 易失性写入,正常读取是 after 易失性读取。
为什么顺序很重要
例如程序是这样写的:
initialized = true;
value = t;
return value
可以 return 一个空值,因为这里的写入不会发生在充当内存屏障的易失性写入之前,因此它不再受益于易失性语义。
Guava Suppliers-class 包含 MemoizingSupplier:
static class MemoizingSupplier<T> implements Supplier<T>, Serializable {
final Supplier<T> delegate;
transient volatile boolean initialized;
// "value" does not need to be volatile; visibility piggy-backs
// on volatile read of "initialized".
transient T value;
MemoizingSupplier(Supplier<T> delegate) {
this.delegate = delegate;
}
@Override public T get() {
// A 2-field variant of Double Checked Locking.
if (!initialized) {
synchronized (this) {
if (!initialized) {
T t = delegate.get();
value = t;
initialized = true;
return t;
}
}
}
return value;
}
@Override public String toString() {
return "Suppliers.memoize(" + delegate + ")";
}
private static final long serialVersionUID = 0;
}
谁能解释一下这条评论是什么意思?
"value" does not need to be volatile; visibility piggy-backs on volatile read of "initialized".
"initialized" 字段上的 volatile 如何影响 "value" 字段? 根据 this 文章,我们可以得到 "initialized" 和 "value" 字段的不一致组合(例如 true+null)。我错了吗?
这句话基本上意味着 value
的读写以某种方式与易失性读写进行排序,以保证写入的值对读取可见。
(简化)证明
如果这个值没有被初始化,程序会执行那两条语句:
value = t; //normal write
initialized = true; //volatile write
如果值被初始化,程序将执行这两个语句:
if(!initialized) { ... } //volatile read
return value; //normal read
多亏了可变语义,可变写入和可变读取之间存在先行关系,return value
中的正常读取保证可以看到 value = t
处的写入。这是有效的,因为正常写入是 before 易失性写入,正常读取是 after 易失性读取。
为什么顺序很重要
例如程序是这样写的:
initialized = true;
value = t;
return value
可以 return 一个空值,因为这里的写入不会发生在充当内存屏障的易失性写入之前,因此它不再受益于易失性语义。