【问题标题】:volatile declaration on int primitive typeint 原始类型的 volatile 声明
【发布时间】:2018-10-26 17:14:37
【问题描述】:

我引用了 Oracle 在 Atomic Access 上的 Java 文档

  • 对于引用变量和大多数原始变量(除 long 和 double 之外的所有类型)而言,读取和写入都是原子操作。
  • 对于声明为 volatile 的所有变量(包括 long 和 double 变量),读取和写入都是原子操作。

我了解volatile 的工作原理。但是提到在第二条语句中为longdouble 变量显式声明volatile 以获得原子访问的要求,是为引用变量和大多数原始变量(除long 和double 之外的所有类型)制作volatile 声明在第一条语句中可选。

但我看到代码在int 原始类型中使用显式volatile 声明来实现原子访问;并且不这样做并不能保证原子访问。

int variable1;          // no atomic access
volatile int variable2; // atomic access

我错过了什么吗?

【问题讨论】:

  • Atomicity is very different to volatility... volatile 最后一行中的关键字用于可见性目的(而不是原子性)。
  • @Oleksandr 该链接肯定有帮助。但实际上我混淆了原子性和可见性,我从答案中得到了澄清。

标签: java concurrency atomic volatile


【解决方案1】:

第一个语句不涉及制作引用变量和原始变量(longdouble除外)volatile

它说 readswrites 除了longdouble 之外的所有引用变量和所有原语都是原子(默认情况下) .要读取写入longdouble原子,它们需要是volatile

原子性与可见性没有任何关系。

同一文档的以下段落

原子操作不能交错,因此可以使用它们而不必担心线程干扰。但是,这并不能消除同步原子操作的所有需要​​,因为仍然可能出现内存一致性错误。使用 volatile 变量可以降低内存一致性错误的风险,因为对 volatile 变量的任何写入都会与后续读取同一变量建立起先发生关系。

所以,像a = 1 这样的语句,其中aint(例如)是原子,但如果你想要volatile,你仍然需要任何后续阅读线程都可以看到分配。

读取/写入 long/double 变量是一个复合动作,使其 volatile 确保它是原子的。

【讨论】:

    【解决方案2】:

    volatile 关键字不仅仅保证原子访问,它还提供可见性保证

    由于doublelong 原语占用的空间是int(64 位)的两倍,因此更新它们的值可以在两个 32 位块中进行。因此,如果没有 volatile,您可以在这两个步骤之间看到 longdouble 的值。这不是其他原始变量的情况。

    但原子访问与可见性不同。 volatile 关键字还保证在写入之后发生的所有其他线程上的变量读取都将看到新值。这就是为什么仍然需要在其他原始类型上使用 volatile 的原因。

    当一个字段被声明为 volatile 时,编译器和运行时 注意到这个变量是共享的,不应该对它的操作 与其他内存操作一起重新排序。可变变量不缓存在 寄存器或缓存中它们对其他处理器隐藏,因此读取 volatile 变量总是返回任何线程最近的写入。

    Java 并发实践:3.1.4 可变变量

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-22
      相关资源
      最近更新 更多