Java内存模型(二)

Java内存模型

重排序

重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的手段。

数据依赖性

如果两个操作访问同一个变量,且这两个操作中有一为写操作,此时这两个操作时间就存在数据依赖性。数据依赖分为三种类型:写后读、写后写、读后写。
上述三种情况,只要重排序这两个操作的执行顺序,程序的执行结果就会改变。因此编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作顺序。
这类所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。

as-if-serial语义

as-if-serial语义的意思是:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不会被改变。as-if-serial语义把单线程程序保护起来,遵循as-if-serial语义的编译器、runtime和处理器保证单线程程序执行的结果与其按照顺序执行的结果一致。

程序顺序规则

1
2
3
double pi = 3.14;           //A
double r = 1.0; //B
double area = pi * r * r; //C

根据happens-before的程序顺序规则,上面计算圆面积的示例代码存在3个happens-before关系:

  • A happens-before B
  • B happens-before C
  • A happens-before C

这里A happens-before B,但在实际执行时B却可以在A之前执行。如果A happens-before B,JMM并不一定要求A在B之前执行。JMM仅仅要求前一个操作对后一个操作可见,且前一个操作按顺序排在后一操作之前。这里操作A的执行结果并不需要对操作B可见;而且重排序操作A和操作B后的执行结果,与操作A和操作B按照A happens-before B顺序执行的结果一致。在这种情况下,JMM会认为这种重排序不非法(not illegal),JMM允许这种重排序。
在计算机中,软件技术和硬件技术有一个共同目的:在不改变程序执行结果的前提下,尽可能提高并行度。

重排序对多线程的影响

多线程程序中,对存在控制依赖的操作重排序,可能会改变程序的执行结果。

顺序一致性

数据竞争与顺序一致性

当程序未正确同步时,就可能会存在数据竞争。Java内存模型规范对数据竞争的定义如下:

  • 在一个线程中写入一个变量;
  • 在另一个线程中读同一个变量;
  • 而且写和读没有通过同步来排序。

当代码中包含数据竞争时,程序的执行往往产生违反直觉的结果。如果一个多线程程序能够同步,这个程序将是一个没有数据竞争的程序。JMM对正确同步的多线程程序的内存一致性做了如下保证:
如果程序时正确同步的,程序的执行将具有顺序一致性——即程序的执行结果与改程序在顺序一致性内存模型中的执行结果相同。

顺序一致性内存模型

顺序一致性内存模型是一个被计算机科学家理想化的理论参考模型。它为程序员提供了极强的内存可见性保证。顺序一致性内存模型有两大特性:

  • 一个线程中的所有操作都必须按照程序的顺序来执行;
  • (不管线程是否同步)所有线程都只能看到一个单一的操作执行顺序。在顺序一致性内存模型中,每个操作都必须原子执行且立刻对所有线程可见。
-------------本文结束感谢您的阅读-------------