我正在阅读JCIP并且无法理解3.3.1中的以下陈述,
只要您可以确保volatile变量仅从SINGLE线程写入,就可以安全地对共享的volatile变量执行读 - 修改 - 写操作。在这种情况下,您将修改限制在单个线程以防止竞争条件,并且volatile变量的可见性保证可确保其他线程查看最新值。
即使volatile变量只是从单个线程写入,它怎么能不提高竞争条件?如果线程A在counter++
为1时执行counter
,则线程B可以在counter+1
写回内存之前进入并获得counter
的陈旧值1。如何确保“防止竞争条件”和“其他线程看到最新的价值”?
附:我知道有同样的问题here,但我没有找到任何令人满意的答案。
volatile变量的读 - 修改 - 写操作如何是线程安全的
一般来说,他们不能。
您引用的文字说:
“只要能确保volatile变量只从SINGLE线程写入,就可以安全地对共享的volatile变量执行读 - 修改 - 写操作。”
这不是线程安全的意思。作为一般性陈述。
即使volatile变量只是从单个线程写入,它怎么能不提高竞争条件?
那么,读取线程没有竞争条件,因为它们只能看到最近写入的变量值。写线程由正常的执行规则控制,因此线程与自身之间不存在竞争条件。
如何确保“防止竞争条件”?
往上看。如果有多个线程更新,您只能参加比赛。从竞争条件的定义来看,这是不言而喻的。
[和]“其他线程看到最新的价值”?
这是Java内存模型指定volatile
的结果。读取volatile变量可以保证看到任何线程最近一次写入的值。
如果线程A在计数器为1时执行计数器++,则线程B可以在计数器+ 1被写回内存之前进入,并获得计数器的失效值1。
在那种情况下,没有竞争条件。线程B看到最近写的counter
值。该计数器尚未更新。这意味着count++
不是原子的。但线程安全和原子并不意味着相同的事情。 Atomic是一个更有力的保证。而且JLS明确指出count++
不是挥发性物质的原子。
现在(很明显)如果你的应用程序有多个共享的volatile变量由不同的(单个)线程更新,那么之前段落的简单推理可能会崩溃。