三、Java内存模型(上)

为什么要学习

我们为什么要学习jvm?給大家一个代码列子,说明一下

public class CatTest {
    public  CatTest() {
        Object t=new Object();
    }
}

接下来执行javac CatTest.java 后面调用javap -v CatTest.class

这里可以看出Object t=new Object(),这代码执行了好多个jvm指令码,但是学过操作系统的肯定知道,cpu执行指令有可能是乱序的,是不是我们的代码就乱了?单线程结果一般都是正确的,但是多线程情况下有可能出问题,但是Java也给我们提供了一些工具,去保证在多线程数据的安全性。

硬件层基础

存储器的层次结构

如何保证数据一致性 

  • 总线锁: 使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占共享内存。
  • MESI Cache缓存一致性协议
    • 每个cache line标记四种状态(invaild、exclusive、modified、shard)
    • 大家可以参考一下别的文章,会理解的更透彻点。

缓存行

  • Cache 中的数据是按块读取的,当CPU访问某个数据时,会假设该数据附近的数据以后会被访问到,因此,第一次访问这一块区域时,会将该数据连同附近区域的数据(共64字节)一起读取进缓存中,那么这一块数据称为一个Cache Line 缓存行。
  • 缓存系统是以缓存行为单位存储的。目前主流的CPU Cache的Cache Line大小都是64字节。
     

不是所有数据都会被缓存,比如一些较大的数据,缓存行无法容下,那么就只能每次都去主内存中读取。

缓存行对齐:伪对齐

缓存行的效率问题?

  • 如果你的X和y在同一块缓存行中,且两个字段都用volatile修饰了那么将来两个线程再修改的时候,就需要将x和y发生修改的消息告诉另外一个线程,让它重新加载对应缓存,然而另外一个线程并没有使用该缓存行中对应的内容,只是因为缓存行读取的时候跟变量相邻,也会需要重新读取。这就会产生效率问题。
  • 解决起来也简单,我们将数据中的两个volatile之间插入一些无用的内存,将第二个值挤出当前缓存行,那么执行的时候,就不会出现相应问题了。提高代码效率。 

执行顺序 

现代cpu执行指令,都会打乱之前的执行顺序去执行。前提是2条指令没有依赖关系。

如何保证特定情况下有序执行:

cpu内存屏障 

Intel设计得比较简单:

①sfence:也就是save fence,写屏障指令。在sfence指令前的写操作必须在sfence指令后的写操作前完成。

②lfence:也就是load fence,读屏障指令。在lfence指令前的读操作必须在lfence指令后的读操作前完成。

③mfence:在mfence指令前得读写操作必须在mfence指令后的读写操作前完成。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值