Java原子特性与《Effective Java》摘录

3
如果根据Effective Java的摘录,Java中int(整数)类型的变量本质上是原子性的,那么为什么我们会在以下示例中看到整数值的不一致状态:https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
语言规范保证读取或写入变量是原子操作,除非变量是long或double类型[JLS, 17.4.7]。换句话说,读取除long或double之外的变量将返回某个线程存储到该变量中的值,即使多个线程同时并且没有同步地修改该变量,也可以保证如此。
以上条款对我来说是相互矛盾的。
2个回答

5
你的错误在于将诸如读取值和写入值这样的单个操作等同于需要多个操作的增量操作。
你链接到的示例包含了对一个int变量进行增减的示例。虽然代码中看起来像是一个操作,但实际上在幕后是两个操作。要进行增量或减量,必须先读取值,然后更改它,最后再写入该值。
这些操作必须被同步以确保线程安全,因为它们由多个操作组成,如果被中断就会导致不正确的值,原因是竞态条件。
即使单个读取或写入操作本身是一致的,一组多个操作也需要进行同步以保持一致性。

在阅读了您的答案后,我认为我有了更好的理解:int是原子性的,这意味着读取整数变量位的操作是原子性的,对吗? 因此,将位写回整数变量也是如此。但是,在读取位之后,执行增量或减量会导致不一致的视图,因为许多线程可能在不同的CPU时间执行。正确吗? - David Prun
1
是的,每个单独的读取或写入都是原子性的,但增加和减少不是原子性的。一个线程可能会中断刚刚读取其值的另一个线程,执行其更改,但当原始线程完成其操作时,中断线程的更改将在没有外部同步的情况下丢失。 - rgettman

1

读取/写入一个 int 是单个原子操作:

int a = 10; // writing
doSomething(a); // reading

另一方面,增量和减量语句由多个操作组成:

a++;

等价于:

a = a + 1; // reading and writing

a可以在读取第二个a之后,写入总数到第一个a之前进行更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接