混合挥发性和非挥发性

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