【问题标题】:local memory visibility with volatile write具有易失性写入的本地内存可见性
【发布时间】:2013-05-23 01:37:08
【问题描述】:

据我了解,新的 java 内存模型要求对 volatile 变量的访问不会随着对其他​​变量的访问而重新排序,因此遵循 code 是正确的:

Map configOptions;
char[] configText;
volatile boolean initialized = false;

// In Thread A
configOptions = new HashMap();
configText = readConfigFile(fileName);
processConfigOptions(configText, configOptions);
initialized = true;

// In Thread B
while (!initialized) 
  sleep();
// use configOptions 

所以当initialized 设置为true 时,配置选项已经初始化,但它是否可见?我的意思是它已经在主内存中了吗?

【问题讨论】:

  • 即使它会起作用,使configOptions 的可见性依赖于另一个变量的可见性是非常脆弱的。您应该尽可能避免:a) 顺序语义(“X 是有效的,因为它发生在 Y 之前”)和 b) 耦合。

标签: java concurrency volatile


【解决方案1】:

所以当 initialized 设置为 true 时,配置选项已经初始化,但它是可见的吗?

是的。只要你做到了volatile 对所有线程都是可见的,并从main memory 读取 根据Java Language Specification

Java 编程语言允许线程访问共享变量(第 17.1 节)。作为一项规则,为了确保共享变量始终如一且可靠地更新,线程应该通过获得一个锁来确保它对这些变量具有独占性,该锁通常对这些共享变量强制互斥。 一个字段可能被声明为 volatile,在这种情况下,Java 内存模型确保所有线程都看到变量的一致值(第 17.4 节)。 `

【讨论】:

  • configOptions 不是易失性的,只有initialized 是易失性的
  • initialized 的读取操作将从主内存中获取,而不是从本地缓存中获取configOptions ' threads will read configOptions`
  • 所有线程都将看到initialized 的最新更新,因为这是不稳定的。
  • 问题不是关于initialized变量,而是关于configOptions
【解决方案2】:

是的。从 Java 5 开始,访问 volatile 变量会创建一个内存屏障,可以有效地将所有缓存变量的副本与主内存同步。

这被称为同步捎带,其中对非同步变量的写入使用对其他变量的后续同步来使用主存储器更新其值。

另外,在 volatile 上读/写是昂贵的。不建议使用它来摆脱无限循环。如果无法避免,至少在某处使用Thread.sleep()

参考资料:
Volatile piggyback. Is this enough for visiblity?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2017-01-17
    • 2023-03-21
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多