除非变量是long或double类型,否则读写单个变量是原子的(语言保证!)。
我在阅读一门课程的幻灯片时发现了这个内容。 这个课程是关于并发性的。
有人能解释一下为什么写入long或double不是原子操作吗? 这真的让我感到惊讶。
除非变量是long或double类型,否则读写单个变量是原子的(语言保证!)。
我在阅读一门课程的幻灯片时发现了这个内容。 这个课程是关于并发性的。
有人能解释一下为什么写入long或double不是原子操作吗? 这真的让我感到惊讶。
由于在机器代码级别上,它是一个多步操作,因此它不是原子性的。也就是说,longs和doubles比处理器的字长要长。
针对Java的情况,只有在使用了volatile
关键字声明时,double和long类型才能够被原子性地读写。
volatile
,否则不能保证对double
或long
进行原子写入。JVM实现可能执行原子写入,但没有Java程序员应该依赖于此。如果存在多线程,则必须防止对半写入的64位数的错误读取。请不要将您的错误直觉发布为事实。 - Basil BourqueJava中,long和double类型在32位机器上不是原子操作,在一些64位JVM上是原子操作。为什么要依赖于机器位数?因为32位机器需要进行两次写入才能完成long(因为long类型有64位)。
要了解详细信息,请阅读此处。
很多程序员可能已经在《Java并发实践》的“3.1.2. 非原子的64位操作”中读到这句话。我参考了最新的JLS17.7. double和long的非原子处理,它们仍然没有声称64位jVM是现今的标准。因此,64位操作被分解成32位操作,这会破坏原子性,在多线程环境下使用会很危险,除非声明为volatile。在Java中,long和double是64位长的。因此,写入和读取操作在Java中不是原子操作。
阅读maaartinus在Java的哪些操作被认为是原子性的?中给出的答案。
阅读Jon Skeet在Java中原始数据类型何时不是线程安全的?中给出的答案。
根据JLS,您可以通过将double和long声明为volatile来使对它们的读写操作具有原子性。但这并不能确保++是原子性的。这需要使用concurrent.atomic包。
阅读Louis Wasserman在此答案中提供的信息。
还有这个博客和评论。
原子变量操作意味着任何线程都可以在没有任何垃圾的情况下从中读取/写入
对于x32和某些x64,非long
/double
的读/写是原子的
,因为存在硬件限制。如果使用volatile
,则会使其成为原子性