Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java易失性和副作用_Java_Concurrency_Atomic_Volatile_Side Effects - Fatal编程技术网

Java易失性和副作用

Java易失性和副作用,java,concurrency,atomic,volatile,side-effects,Java,Concurrency,Atomic,Volatile,Side Effects,Oracle关于原子访问(at)的文档中说: “volatile变量建立“发生在之前”关系……这意味着……当线程读取volatile变量时,它不仅看到volatile的最新更改,还看到导致更改的代码的副作用。” 我很难理解这一点。我理解volatile变量是如何工作的(在>=Java5中),但我想知道Java是如何决定影响volatile变量变化的哪一方面的 所以我想我的问题是:这种保证有什么副作用 编辑: 因此,我了解到,如果线程A修改一个易失性变量,然后线程B读取它,那么在写入易失性变量之前

Oracle关于原子访问(at)的文档中说:

“volatile变量建立“发生在之前”关系……这意味着……当线程读取volatile变量时,它不仅看到volatile的最新更改,还看到导致更改的代码的副作用。”

我很难理解这一点。我理解volatile变量是如何工作的(在>=Java5中),但我想知道Java是如何决定影响volatile变量变化的哪一方面的

所以我想我的问题是:这种保证有什么副作用

编辑:


因此,我了解到,如果线程A修改一个易失性变量,然后线程B读取它,那么在写入易失性变量之前,线程A中发生的所有写入都会与线程B“一致”(即线程A执行上述写入操作的变量的缓存值在线程B中无效)。如果我错了,请纠正我。

大多数多处理器缓存都有一致性机制,因此惩罚不如刷新所有缓存那么严重

线程中在执行操作之前写入volatile的任何写入操作都将被执行此操作之后读取volatile的线程看到。

举个例子。创建对象时,许多事情都发生在幕后:

MyClass c=new MyClass();
分配内存,调用构造函数,并将内存位置分配给变量c。允许JVM对这些操作重新排序。如果分配了内存、分配了值,并且线程在调用构造函数之前中断并使用该值,则会导致问题

volatile MyClass c=new MyClass();

根据第1.5条规则,任务保证是这些事件中的最后一个。“副作用”是分配和构造函数调用。

您确实对缓存的工作方式有误解,但易失性写入会刷新写入缓冲区,而不会刷新缓存(缓存可以手动刷新,但通常您不希望这样)。我的误解到底是什么?听起来你的答案可能与汤姆·霍丁的不同——也许你想写一个替代答案?不,这与他的答案并不矛盾,尽管它(他的答案)并不完全完整。缓存不会被刷新(这只会破坏任何性能),但只会使修改后的缓存线保持一致(简单地说)。此外,它还确保没有推测性的读写(这一点非常重要)。因此,当CPU恢复时,所有其他人都会/可能知道该写操作(以及所有以前的写操作)。一般来说,所有CPU都会在某一点上使写操作可用/可见,但只有现在才允许写操作。我不认为这是一个很好的解释缓存一致性如何工作的领域。顺便说一句,“刷新”是指“逐出”吗?刷新缓存通常意味着逐出其条目,而不仅仅是传播写操作。我不清楚我的意思。不要理会那句话。问:你所说的“过去的书写”是什么意思?啊,这很有道理。那么缓存中特定线程的所有内容都将被刷新?Java没有办法表明一个变量肯定不会被另一个线程访问(因此不需要刷新)?或者编译器/解释器可能会对此进行某种优化?另外,我喜欢你的措辞“在这样做之后”-因此从线程A到线程B中已更改的非易失性的读取可能已经过时,直到线程A读取由线程B更改的易失性为止,对吗?@BT我不是缓存一致性方面的专家。必须确保没有其他缓存“认为”它具有缓存线的干净副本。当然没有必要使一切都无效。局部变量可以保留在寄存器中。可以保留堆分配的对象,但这几乎可以忽略不计是。@BT它完全取决于所使用的缓存一致性协议。一般来说,我们只需要传播所有修改过的缓存线的写入(如果协议提供了这些信息——不知道ARM,但更复杂的桌面CPU肯定会这样做)而不是整个缓存。这是一个合理的例子,但它没有解释java如何决定要传播的方面或何时。汤姆的回答非常简洁地解释了这一点。