混合挥发性和非挥发性
Mixing volatile and non-volatile
我的问题适用于最初为 null
的字段,然后初始化为非 null
值,然后不再更改。
由于此字段需要尽快对所有线程可用,因此我需要使用 volatile
。
但是如果我想尽可能避免 volatile
访问的开销(即当非 volatile
字段就足够时),下面的代码是否有意义?
public class User {
private String nonVolatileName;
private volatile String volatileName;
public String getName() {
final String name = nonVolatileName;
return name != null ? name : volatileName;
}
private void initName() {
volatileName = nonVolatileName = expensiveComputation();
}
…
}
是的,代码会起作用,因为 "A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field." [1]
return name != null ? name : volatileName;
所以只要 name == null
你就会强制从一个 volatile 变量读取直到它不为空(即 expensiveComputation
已经完成),鉴于 happen before 语义确保你看到从那时起 nonVolatileName
中的非空值。另见此处 [2]
虽然向你的同事解释这个很有趣
[1] https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5-320
[2]Volatile variables and other variables
我的问题适用于最初为 null
的字段,然后初始化为非 null
值,然后不再更改。
由于此字段需要尽快对所有线程可用,因此我需要使用 volatile
。
但是如果我想尽可能避免 volatile
访问的开销(即当非 volatile
字段就足够时),下面的代码是否有意义?
public class User {
private String nonVolatileName;
private volatile String volatileName;
public String getName() {
final String name = nonVolatileName;
return name != null ? name : volatileName;
}
private void initName() {
volatileName = nonVolatileName = expensiveComputation();
}
…
}
是的,代码会起作用,因为 "A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field." [1]
return name != null ? name : volatileName;
所以只要 name == null
你就会强制从一个 volatile 变量读取直到它不为空(即 expensiveComputation
已经完成),鉴于 happen before 语义确保你看到从那时起 nonVolatileName
中的非空值。另见此处 [2]
虽然向你的同事解释这个很有趣
[1] https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5-320
[2]Volatile variables and other variables