java内存模型(JMM)
一、前言多核并发缓存架构说起java并发内存模型首先了解一下多核并发缓存架构就是我们服务器的cpu和主内存之间因为2者运算速度有较大差距所以在cpu与主内存之间有一道cup缓存cpu通过cpu缓存读取数据进而让cpu发挥出性能优势二、JMM内存模型java内存模型和和cpu缓存模型类似是基于cpu缓存模型建立的三、示例说明为了便于理解我们结合一段代码示例来看下结果122行代码改了flag但是可以看到结果并没有打印出线程1感知到flag变成true说明线程t1里并没有感知到flag变成true那么我们接下来将flag加上volatile再尝试运行结果2我们发现加上volatile修饰后打印出了线程1感知到flag变成true说明线程t1感知到flag变成true通过结果1可以说明线程内部确实是读取线程内部的数据副本进行代码处理通过结果2则说明可以通过volatile来实现共享变量的可见性并发编程的3大特性可见性、有序性、原子性好的那么volatile是怎么实现可见性的呢那就需要结合java的JMM数据原子操作指令以及缓存一致性协议来一起看下JMM数据原子操作read(读取从主内存读取数据load载入将主内存读取到的数据写入工作内存use使用从工作内存读取数据来计算assign赋值将计算好的值重新赋值到工作内存中store存储将工作内存数据写入主内存write写入将store过去的变量值赋值给主内存中的变量lock锁定将主内存变量加锁标识为线程独占状态unlock解锁将主内存变量解锁解锁后其他线程可以锁定该变量缓存一致性协议MESI多个cpu从主内存读取同一个数据到各自的高速缓存当其中某个cpu修改了缓存里的数据该数据会马上同步回主内存其它cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效缓存加锁缓存锁的核心机制是基于缓存一致性协议来实现的一个处理器的缓存回写到内存会导致其他处理器的缓存无效IA-32和Intel64处理器使用MESI实现缓存一致性协议好的那其实上述代码对应的JMM原子操作流程如图结合图中箭头大家可以知道主线程是获取并修改flag的值的那线程t1使用flag变量的时候是通过总线嗅探机制图中绿色发现flag被修改了接下来会把自己的工作内存中的flag变量副本失效从而从主内存的flag变量重新read、load到线程t1的工作内存中。这就是volatile的可见性原理。好的那么大家还记得volatile还保证了有序性这个是怎么实现的呢首先java底层是有指令重排序的就是在不影响单线程执行结果的前提下计算机为了发挥最大新能会对机器指令重新排序优化具体原则是as-if-serial与happens-before具体不展开了大家简单理解一下1、可以重排序int a 1;int b2;这2行代码执行顺序不影响结果所以可以重排序2、不可以重排序int a 1;int b a;显然执行顺序影响结果所以不可以重排序那关键就来了既然有可能发生重排序volatile就是通过解决重排序来保障有序性的这个实现过程叫做内存屏障对应规范如下屏障类型指令说明LoadLoadLoad1;LoadLoad;Load2保证load1的读取操作在load2及后续读取操作之前执行StoreStoreStoreStoreStore;Store2在store2及其后的写操作执行前保证store1的写操作已刷新到主内存LoadStoreLoad1; LoadStore; Store2在stroe2及其后的写操作执行前保证load1的读操作已读取结束StoreLoadStore1;StoreLoad:Load2保证store1的写操作已刷新到主内存之后load2及其后的读操作才能执行java规定了volatile需要实现的内存屏障我们举个例子说明一下int volatile a 1;int b a;则对应的屏障StoreStore屏障a1://volatile写a为volatile变量StoreLoad屏障b a;//volatile读LoadLoad屏障LoadStore屏障这样保障了代码的执行顺序进而保障有序性