volatile变量的读 - 修改 - 写操作如何是线程安全的

时间:2017-12-19 02:58:10

标签: java multithreading

我正在阅读JCIP并且无法理解3.3.1中的以下陈述,

  

只要可以确保volatile变量仅从SINGLE线程写入,就可以安全地对共享的volatile变量执行读 - 修改 - 写操作。在这种情况下,您将修改限制在单个线程中以防止竞争条件,并且volatile变量的可见性保证可确保其他线程查看最新值。

即使volatile变量只是从单个线程写入,它怎么能不提高竞争条件?如果线程A在counter++为1时执行counter,则线程B可以在counter+1写回内存之前进入并获得counter的失效值1 。如何确保"防止竞争条件"和"其他线程看到最新的值" ??

P.S。我知道那里有同样的问题here,但我没有找到任何令人满意的答案。

1 个答案:

答案 0 :(得分:4)

  

volatile变量的读 - 修改 - 写操作如何是线程安全的

一般情况下,他们不能。

您引用的文字说:

  

“只要对共享的volatile变量执行读 - 修改 - 写操作是安全的,因为您可以确保volatile变量只从SINGLE线程写入。”

这不是线程安全的意思。作为一般性陈述。

  

即使volatile变量只是从单个线程写入,它怎么能不提高竞争条件?

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

  

如何确保“防止竞争条件”?

见上文。如果有多个线程更新,您只能参加比赛。从竞争条件的定义来看,这是不言而喻的。

  

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

这是Java内存模型指定volatile的结果。读取volatile变量可以保证看到任何线程最近一次写入的值....

  

如果线程A在计数器为1时执行计数器++,则线程B可以在计数器+ 1被写回内存之前进入并获得计数器的失效值1。

在那种情况下,没有竞争条件。线程B看到最近写入的counter值。该计数器尚未更新。 这意味着count++ 不是原子。但线程安全和原子并不意味着相同的事情。 Atomic是一个更有力的保证。并且JLS明确指出count++对于挥发物而言不是原子的。

现在(显然)如果你的应用程序有多个共享的volatile变量由不同的(单个)线程更新,那么之前段落的简单推理可能会崩溃。