boo*_*lan 10 java concurrency atomic volatile
我引用了Oracle关于Atomic Access的Java文档
- 读取和写入对于引用变量和大多数原始变量(除long和double之外的所有类型)都是原子的.
- 对于声明的所有变量
volatile(包括长变量和双变量),读取和写入都是原子的.
我明白是怎么volatile运作的.但是提到volatile明确声明for long和double变量以在第二个语句中获得原子访问的要求,是在第一个语句中volatile为引用变量和大多数原始变量(除long和double之外的所有类型)声明可选.
但我看到的代码使用原始类型的显式volatile声明int来实现原子访问; 而不这样做不保证原子访问.
int variable1; // no atomic access
volatile int variable2; // atomic access
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
第一个语句不是指引用变量和原始变量(除了long和double)volatile.
它表示读取和写入所有引用变量和所有原语,除了long和double是原子的(默认情况下).为了使读取和写入的long和double 原子他们需要volatile.
原子性与可见性无关.
以下段落在同一个doc上
原子动作不能交错,因此可以使用它们而不必担心线程干扰.但是,这并不能消除所有同步原子操作的需要,因为仍然可能存在内存一致性错误.使用volatile变量可降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系.
所以,像语句a = 1哪里a是int(举例来说)是原子,但你仍然需要有挥发性,如果你想分配给对任何可见的后续读线程.
读取/写入long/double变量是一个复合动作,使其变为volatile是确保它是原子的.
该volatile关键字不仅可以保证原子访问,还具有可见性保证.
因为double和long原语占用int(64位)更新空间的两倍,它们的值可以在两个32位块中发生.因此,如果没有易失性,您可以看到这两个步骤之间long或double之间的值.其他原始变量不是这种情况.
但原子访问与可见性不同.该volatile关键字还保证在写入之后发生的其他线程上的变量的所有读取都将看到新值.这就是为什么volatile仍然需要使用其他原始类型的原因.
当一个字段被声明为volatile时,编译器和运行时会注意到该变量是共享的,并且对它的操作不应该与其他内存操作重新排序.易失性变量不会缓存在寄存器或缓存中,而是隐藏在其他处理器中,因此读取volatile变量始终会返回任何线程的最新写入.
Java Concurrency in Practice:3.1.4易失性变量