Java内存模型_JMM

多核并发缓存架构:
在这里插入图片描述
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修饰的变量进行操作时,会产生<=理想值的情况;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值