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并发编程的艺术)

posted @ 2020-10-12 23:57  α_伊卡洛斯  阅读(530)  评论(0)    收藏  举报