首先计算机运行程序需要将内存里面的数据读取到CPU中,CPU对数据进行处理,然后CPU从内存读入到CPU这种代价是很大的,所以CPU根内存又加入了一道高速缓存
假设一个线程(CPU1)为变量 a赋值 a = 3; 那么CPU2,CPU3,在上面条件下能看到3这个值?如果缺少了同步,就会有很多因素导致CPU1,CPU2 可能无法立即甚至永远看不到这个a的值被CPU1更改的结果,因为编译器生成指令的次序可以不同于源代码编写的次序,处理器可以乱序或者并行地执行指令。如果这种情况发生在单线程下面,这种情况不会产生什么样的影响。
java内存模型(JMM)规定了JVM的一种最小保证,什么时候写入一个变量会对其他线程可见。具体体现在,java存储模型定义是通过动作的形式秒杀的,所以动作,包括变量的读和写,监视器枷锁和释放锁,线程的启动等
JMM 为内部动作定义了一个偏序关系,叫做 happens-before,即按照一定的先后顺序。当一个变量被多个线程读取,且至少被一个线程写入时,如果读写操作并未依照hahappens-before排序,就会产生数据竞争。
happens-before的法则包括:
程序次序法则:线程中的每个动作A,都 happens-before 于该线程中的每一个动作B ,其中 在程序中,所有的动作B都出现在动作A之后。
监视器锁法则:对一个监视器锁的解锁 happens-before 于每一个后续对同一个监视器锁的加锁。
volatile 变量法则:对volatile 域的写入操作 happens-before 于每一个后续对统一个域的读操作。
线程启动法则:在一个线程里,对Thread.start()的调用会happens-before于每一个启动线程中的动作。
线程终结法则:线程中的任何动作都happens-before 于其他线程检测到这个线程已经终结.或者从Thread.join调用成功返回,或者Thread.isAlive返回false。
终结法则:一个对象的构造函数的结束 happens-before 于这个对象finalizer的开始。
传递性: 如果a happens-before 于 b, 且 b happens-before 于c,则a happens-before于c。
待更新。。。