我知道有关挥发性的问题很多,但我对此讨论感到困惑: Java: how volatile guarantee visibility of "data" in this piece of code?
我读过的每个网站都说变量可以存储在缓存中(使这个值对另一个线程不可见)我甚至发现了这个例子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?
修改 我刚读完Peter Lawrey的文章 http://vanillajava.blogspot.com.es/2012/01/demonstrating-when-volatile-is-required.html 并且他写道:“如果没有易失性,这会以多种可能的方式发生故障。一种方式是两个线程都认为他们已经改变了价值并等待另一个,即每个都有自己的值的缓存副本“
所以我更加困惑......关于那个
对于这个可能很愚蠢的问题感到抱歉,但我对此感到很困惑。
答案 0 :(得分:3)
大多数程序(包括JVM)都没有明确地将变量放在任何特定的缓存中。 JIT做出的唯一决定是
您唯一的选择是变量是在对象中还是在堆栈中。 (你也可以选择完全避免使用变量)注意,如果你将字段放在一个对象中,如果它可以避免创建对象,jit仍然只能将它放在堆栈中。
使num2
volatile提供的唯一可见性保证是,如果您看到num2 == 20,则必须看到num1 == 10.您还可以保证在其他线程中的某个位置会看到num2 == 20 。
您可能会看到num3 == 3或num3 == 30.您可能永远不会在另一个线程中看到num3,因为它不是volatile或final。如果在第二次写入num2之前在另一个线程中读取该字段,您可能会看到num3 == 0这是未初始化的值。
每个都有自己的值的缓存副本。
这不是由Java确定的,而是CPU的实现细节。每个核心都有自己的x64,Sparc和ARM中的L1和L2缓存。这些缓存对于每个核心来说都是本地的速度,这意味着它们可能彼此不同步。确保它们始终保持同步会大大降低它们的速度。
答案 1 :(得分:0)
当您查找此类行为的确切描述时,查看Java Language Specification总是好的。在链接的章节中,您将找到有关线程行为和编译器重新排序的信息以及volatile
如何在此处发挥作用。
答案 2 :(得分:0)
作业的顺序不受volatile
的影响。关键字volatile
保证多个线程访问例如int-value' see'相同的价值。该变量的值永远不会被线程本地缓存:所有读取和写入将直接进入"主存储器"。对变量的访问就好像它被包含在同步块中一样,自身同步。