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