1.数据竞争与 顺序一致性保证
当程序未正确同步时,就可能会存在数据竞争。
JMM对正确同步的多线程程序的内存 一致性做了如下保证:
如果程序是正确同步的,执行将具有顺一致性(sequentially consistent)-- 即程序的执行结果与该程序在顺序一致性内存模型中执行结果相同。 这里同步是指广义上的同步,包括对常用同步原语(synchronized ,volatile和 finalfinalfinalfinal )的正确使用。
2.顺序一致性内存模型
两大特性:
- 一个 线程中的所有操作必须按照程序的顺来执行。
- (不管程序是否同步) 所有线程都只能看到一个单一的操作执行顺序。 在顺序 一致性内存模型中, 每个操作都必须原子执行且立刻对所有线程可见。
但是,未同步程序在 JMM中不但整体的执行顺序是无序的 ,而且所有线程看到操作执行顺序也可能不一致。
比如,在当前线程把写过的数据缓存在本地内中,在还没有刷新到主内存之前,这个写操作仅对当线程可见; 从其他线程的角度来观察,会认为这个写操作根本还没有被当前线程执行。只有当线程把本地内存中写过的数据刷新到主内存之后,这个写操作才能对其他线程可见 。在这种情况下,当前线程和其它看到的操作执行顺序将不一致。
3.同步程序的顺序一致性效果
从这里我们可以看到 JMM在具体实现上的基本方针:在不改变 (正确同步的)程序执行结果的前提下,尽可能地为编译器和处理器的优化打开方便之门。
4.未同步程序的执行特性
对于未同步或未正确的多线程程序,JMM只提供最小安全性:线程执行时读取到的值,要么是之前某个线程写入默认(0,null,false),JMM保证线程读操作取到的值不会无中生保证线程读操作取到的值不会无中生有(out of thin air)的冒出来。为了实现最小安全性,JVM在堆上分配对象时,首先会清零内存空间,然后才会在上面分配对象(JVM内部会同步这两个操作)。因此,在已清零的内存空间(prepre-zeroed memory)分配对象时,域的默认初始化已经完成了。
未同步程序在两个模型中的执行特性有下面几个差异:
- 1.顺序一致性模型保证单线程内的操作会按按程序的顺序执行,而JMM不保证单线程内的操作会按程序顺执行(比如上面正确同步的多线程程序在临界区内的重排序)。
- 2.顺序一致性模型保证所有线程只能看到一致的操作执行,而JMM不保证所有线程能看到一致的操作执行顺序。
- 3.JMM不保证对64位的long型和double型变量的读/写操作具有原子性,而顺序一致性模型保证对所有的内存读/写都具有原子性。
从JSR-133内存模型开始内存模型开始(即从JDK5开始),仅仅只允许把一个64long/double型变量的写操作拆分为两个32位的写操作来执行,任意读操作在JSR-133中都必须具有原子性(即任意读操作必须要在单个事务中执行)。