JAVA内存模式-7-总结

处理器内存模型

顺序一致性内存模型是一个理论参考模型,而处理器内存模型在设计时会对顺序一致性模型做一些放松,毕竟如果完全按照顺序一致性的话,处理器很多优化会被禁止。

在两个操作之间不存在数据依赖性的前提下,处理器会对不同类型读、写操作组合的执行顺序放松,常见的有:

  1. 放松程序中写-读操作的执行顺序,叫做total store ordering内存模型,简称TSO。
  2. 在前面1的基础上,继续放松程序中写-写操作的执行顺序,叫做partial store order内存模型,简称PSO。
  3. 在前面1和2的基础上,继续放松程序中读-写、读-读操作的顺序,叫做relaxed memory order内存模型,简称RMO、PowerPC内存模型。

由于常见处理器内存模型比JMM要弱,因此JMM在生成字节码的时候,在指令序列适当位置插入内存屏障指令来禁止处理器重排序。同时由于各个处理器内存模型强弱的不同,为了在不同处理器平台展示一致的内存模型,JMM在不同处理器中需要插入的内存屏障的数量、类型各不相同。

JMM是一个语言级的内存模型。

处理器内存模型是硬件级的内存模型。

顺序一致性内存模型是一个理论级参考模型。

JMM的设计

在设计JMM时需要考虑两个关键因素:

  1. 程序员对内存模型的使用。从程序员角度来看,内存模型易于理解、易于编程,因此程序员希望是越接近顺序一致性内存模型越好。
  2. 编译器和处理器对内存模型的实现。希望完全不遵守顺序一致性内存模型,因为这样才能尽可能的优化来提高性能。

程序员希望完全遵守顺序一致性内存模型,编译器和CPU不希望遵守顺序一致性内存模型,那JMM是怎么做到平衡的呢???????????????

JMM针对重排序分为2类:

  1. 会改变程序执行结果的重排序,这种重排序JMM会要求编译器和CPU必须禁止此类型重排序。
  2. 不会改变程序执行结果的重排序,这种重排序JMM不对编译器和CPU做要求。

JSR-133对旧内存模型的修改

  1. 增强volatile内存语义。旧模型允许volatile变量与普通变量重排序,因为CPU会对读-读、写-写、读-写、写-读重排序,鬼知道会重排序成啥样,因此JSR-133限制volatile变量与普通变量的重排序,使得volatile写-读跟锁释放-获取具有相同的内存语义,例如:

int a = 0

volatile b = 0;

int c = b;// 操作1

a = 100;// 操作2

b = 100;// 操作3

c......

旧内存模型可能的重排序结果:(有多种,下面只是其中一种)

b=100;

c=b;

a=100;

新内存模型的重排序结果

c=b

LoadLoad

LoadStore

a=100

StoreStore

b=100

StoreLoad

这种情况下,编译器通过内存屏障指令禁止重排序了,至于CPU针对内存屏障指令的二次优化,这里不提了。

  1. 增强final的内存语义。旧模型中多次读取同一个final变量的值可能不相同,因此JSR-133为final增加了读写重排序规则,从而让final具有初始化安全性,例如:

class T{

private int a;

private final int b;

private T t;

private T(){

a=100;

b=100;

}

public static T getT(){

t = new T();

return t;

}

public static int getB(){

return b;

}

public static int getA(){

Return a;

}

}

旧模型可能的重排序:(这种不存在数据依赖性的前提下,编译器和CPU重排序后的结果,鬼知道呢)

class T{

private int a;

private final int b;

private T t;

private T(){

}

public static T getT(){

t = new T();

return t;

}

public static int getB(){

return b;

}

public static int getA(){

a=100;

b=100;

return a;

}

}

因为不存在数据依赖性,这种重排序组合是可能存在的。

新内存模型:

首先,final的初始化必须包含在构造方法内;

其次,构造方法才去把对象引用传出去;

最后,先获取对象引用,然后才去读final变量;

你可能感兴趣的:(Java)