多核并发缓存架构:
CPU的效率会受限于RAM,所以便产生了上图的缓存架构;
Java内存模型_JMM:
如何来证明JMM的结构如上图所示呢?
我们来看一个例子:
输出结果:
首先我们先来分析这个程序:
依次启动两个线程,第一个线程执行完输出‘等待数据’之后,由于静态变量的值为false,则陷入了无线循环;第二个线程输出了‘准备数据’之后,将静态变量的值改为true,然后输出‘准备数据结束’;
此时你会发现:虽然在成功执行第二个线程之后,静态变量的值被改变,但是第一个线程并没有因此停止循环,未能输出‘success’;
彷佛第一个线程并没有感知到静态变量值的改变,因此也就可以推断出JMM的结构原理;
那么如何能让上述程序达到想要的结果(线程1感知到值的改变,结束循环,继续执行)呢?
在静态变量前加上 volatile 关键字!!!
此时(线程1跳出了无线循环):
JMM数据原子操作:
上例中发生的原子操作如图:
(注意:store时数据便移到了主内存)
若采用总线加锁的方式:则假设线程2在read数据时,成功将该变量加锁,然后必须等到线程2将数据write回1该变量之后解锁,期间不允许其他CPU去读取该数据;
若多个线程访问一个对象,则只有一个线程可以访问成功并加锁成功,其他线程需要排队等待------->效率太低
若采用MESI缓存一致性协议:
//总线嗅探机制会在感知到变量发生改变之后,立刻让CPU中的有关变量失效;
若线程继续需要该变量,则会重新read该值;
volatile:保证共享变量在多个线程之间的可见性;
volatile可见性底层实现原理:
其中 [rsp] 指的便是寄存器,也就是工作内存;
该行操作对应JMM原子操作中的 assign 操作;
1.为什么volatile修饰的变量在修改之后,立即会store->write到主内存中?
因为MESI协议会造成其他缓存了该内存地址的数据无效性,立即回写会保证其他线程尽可能小的受影响(减少不一致的时间差),保证了时效性;
2.明明数据在store就已经到了内存区,那为什么要在write之后响应呢,而不是store呢?
因为volatile机制会在store之前加上一个lock,然后再write之后unlock,所以只有write之后的重读会让其他线程可以保证一定读到最新的数据;
(否则可能会出现write还没成功执行,其他线程便已经重新读了数据,此时读的还是旧的数据)
volatile可见性、原子性、有序性:
我们来看一个例子:
该程序想通过创建10个线程来同时对同一个静态变量进行自增1000次:
但是结果会是1000*10 吗?
运行之后你会发现,结果会出现<= 10*1000的情况,且每次的结果可能不一样;
以其中两个线程为例分析:
若出现如下形况:两个线程同时做完了assign操作,但是只有一个成功lock–>store–>write写入内存,另一个线程感知到数据的变动,此时会让工作区中变量失效,则这意味着这部分操作可能丢失掉了,也因此产生了<=理想值的情况;
由于协议的存在,时间差会导致某线程产生无效的操作;
则多个线程对volatile修饰的变量进行操作时,会产生<=理想值的情况;