Java 易失性变量的读修改写操作如何是线程安全的

Java 易失性变量的读修改写操作如何是线程安全的,java,multithreading,Java,Multithreading,我正在阅读JCIP,无法理解3.3.1中的以下语句 对共享的易失性变量执行读-修改-写操作是安全的,只要可以确保仅从单个线程写入易失性变量。在本例中,您将修改限制在单个线程中,以防止争用情况,并且volatile变量的可见性保证确保其他线程看到最新的值 即使volatile变量只从单个线程写入,它怎么能不引发争用条件呢?如果线程A在counter为1时执行counter++,线程B可能会在counter+1写回内存之前进入,并获得counter的陈旧值1。如何确保“防止争用条件”和“其他线程看到

我正在阅读JCIP,无法理解3.3.1中的以下语句

对共享的易失性变量执行读-修改-写操作是安全的,只要可以确保仅从单个线程写入易失性变量。在本例中,您将修改限制在单个线程中,以防止争用情况,并且volatile变量的可见性保证确保其他线程看到最新的值


即使volatile变量只从单个线程写入,它怎么能不引发争用条件呢?如果线程A在
counter
为1时执行
counter++
,线程B可能会在
counter+1
写回内存之前进入,并获得
counter
的陈旧值1。如何确保“防止争用条件”和“其他线程看到最新值”

p、 我知道有一个相同的问题,但我没有找到任何令人满意的答案

易失性变量的读修改写操作如何是线程安全的

一般来说,他们不能

你引用的文本说:

“只要可以确保仅从单个线程写入易失性变量,就可以安全地对共享易失性变量执行读-修改-写操作。”

这不是线程安全的含义。作为一般性声明

即使volatile变量只从单个线程写入,它怎么能不引发争用条件呢

嗯,对于读取线程来说没有竞争条件,因为它们只会看到变量最近写入的值。而写线程是由正常的执行规则控制的,因此线程和自身之间不存在竞态条件

如何确保“防止种族状况”

见上文。只有在有多个线程更新的情况下,才能进行竞争。从种族条件的定义来看,这是不言而喻的

[和]“其他线程可以看到最新的值”

这是Java内存模型指定的关于
volatile
的结果。对易失性变量的读取保证可以看到最近一次写入的值。。。无论如何


若线程A在计数器为1时执行计数器+,线程B可能在计数器+1写回内存之前进入,并获得计数器的陈旧值1

在这种情况下,不存在竞争条件。线程B正在看到最近写入的
计数器的值。计数器尚未更新。
这意味着,
count++
不是原子的。但是线程安全和原子性并不是一回事。原子能是更有力的保证。JLS明确指出,
count++
对于挥发物来说不是原子的


现在(显然)如果应用程序中有多个共享的易失性变量由不同的(单个)线程更新,那么前面几段的简单推理可能会失败。

“线程B可能会在计数器+1写回内存之前进入”。是的,这意味着线程B在读取数据时获得了最新的值。这就是它所保证的。在你看来,这是如何创造比赛条件的?规格尽可能清楚。在您的示例中,在
计数器+1
写入内存之前,包括线程B在内的所有线程都将看到1。一旦写下来,他们都会看到2。有些线程绝对看不到1,有些线程看不到2。@tsolakp你说得对。我对“陈旧价值观”的概念感到困惑。这里,线程B读取“更新”值,而不是“过时”值,因为这是A最后一次写入内存的值。线程A和B在这里完全同步。@Erwin,在阅读了您所说的内容后,现在有了意义。谢谢。只是好奇,如果使用单编写器策略,使用原子
lazySet
更新状态是否安全?此外,符合单编写器策略的“感知”原子性与线程安全性之间是否存在任何差异?