Java volatile keyword



我知道关于volatile有很多问题,但我只是从这次讨论中感到困惑:Java:易失性如何保证";数据";在这段代码中?

我读到的每个网站都说变量可以存储在缓存中(使这个值对其他线程不可见)我甚至发现了这个例子https://dzone.com/articles/java-volatile-keyword-0

所以我的第一个问题是:Java是否将变量值存储在缓存中(在哪一个中?l1 l2或l3)

我的另一个问题是可见性部分。例如:

public int num1 = 1;
public int num2 = 2;
public int num3 = 3;
public int num4 = 4;
public int num5 = 5;
...
num1 = 10;
num2 = 20;
num3 = 30;
num4 = 40;
num5 = 50;

在本例中,变量的执行顺序没有得到保证。如果我将num2设为volatile,它会向我保证num1、num2和num3的顺序执行将与其定义的完全相同,但它不能向我保证num4和num5?

编辑我刚读完彼得·劳瑞的文章http://vanillajava.blogspot.com.es/2012/01/demonstrating-when-volatile-is-required.html他写道:"如果没有volatile,这有很多可能的方式。一种方式是两个线程都认为自己已经更改了值,并在等待另一个,即每个线程都有自己的值缓存副本。"

Sooo我更困惑了。。关于

很抱歉问了这个可能很愚蠢的问题,但我真的很困惑。

包括JVM在内的大多数程序都不会显式地将变量放入任何特定的缓存中。JIT做出的唯一决定是

  • 它是否完全消除了变量
  • 它会把它放在寄存器里吗?是哪一个
  • 它会把它放在内存的堆栈上吗?(以及相对于堆栈顶部的位置)
  • 它会把它放在堆上的一个对象中吗?(以及对象中的位置)

您唯一的选择是变量是在对象中还是在堆栈中。(你也可以选择完全避免使用变量)注意,如果你把字段放在一个对象中,jit仍然可以只把它放在堆栈中,如果它可以避免创建对象的话。

使num2易失性提供的唯一可见性保证是,如果看到num2==20,则必须看到num1==10。您还可以保证在其他线程中的某个时刻会看到num2==20。您可能会看到num3==3或num3==30。您可能永远不会在另一个线程中看到num3,因为它不是易失性的或最终的。如果在第二次写入num2之前在另一个线程中读取该字段,您可能会看到num3==0,这是未初始化的值。

每个值都有自己的缓存副本。

这不是由Java决定的,而是CPU的实现细节。每个核心在x64、Sparc和ARM中都有自己的L1和L2缓存。为了提高速度,这些缓存是每个核心的本地缓存,这意味着它们可能彼此不同步。确保它们始终保持同步会大大降低速度。

当您寻找此类行为的确切描述时,最好查看Java语言规范。在链接的章节中,您将在此处找到有关线程行为和编译器重新排序以及volatile如何发挥作用的信息。

分配的顺序不受volatile的影响。关键字volatile保证访问一个int值的多个线程"看到"相同的值。这个变量的值永远不会缓存到线程本地:所有的读取和写入都将直接进入"主内存"。对变量的访问就像它被封闭在一个同步块中,在自身上同步。

最新更新