JMM(Java内存模型)不保证对64位long型和double型变量的写操作具有原子性
- 在计算机中,数据通过总线在处理器和内存之间传递。每次处理器和内存之间数据传递都是通过一系列步骤来完成,被称为“总线事务”。包括读事务和写事务。总线会同步这些事务,在一个处理器执行总线事务期间,总线会禁止其他处理器和I/O设备执行内存的读和写。
- 假设处理器A,B,C同时向总线发起总线事务,总线会进行公平仲裁。假设A获胜,此时A执行总线事务,B和C要等待其完成后再进行总线事务,若A在执行总线事务期间,处理器D也向总线发起了总线事务,此时处理器D的请求也会被总线禁止。
- 总线的工作机制类似串行化处理。在任意时间点最多只能有一个处理器可以访问内存。这个特性确保了单个总线事务之中的内存读写操作,具有原子性。
- 在32位机处理器上,如果要求对64位数据的写操作具有原子性,开销较大,为照顾这种处理器,Java鼓励但不强求JVM对64位的long型变量和double型变量的写操作具有原子性。当JVM在这种处理器上运行的时候,可能会把64位的long/double型变量的写操作,拆分为两个32位的写操作来执行。这两个写操作可能会被分配给不同的总线事务中执行,此时对这个64位变量的写操作将不具有原子性。
处理器B将看到仅仅被处理器A“写了一半”的无效值。
- 注意,在JSR-133之前的旧内存模型中,64位long/double型变量的读/写操作均可被才分为两个32位的读/写操作。从JSR-133内存模型开始(JDK5),仅仅只允许把64位long/double型变量的写操作拆分为两个32位的写操作来执行,但任意的读操作必须具有原子性(即任意读操作必须要在单个读事务中执行)。
(参考自Java并发编程的艺术)
评论