JMM多线程内存模型

多核并发缓存

JMM多线程内存模型

volatile 能保证数据的可见性

volatile的作用可以强制线程从公共内存中读取变量的值,而不是从工作内存中读取

8大原子操作:

用于开发jvm时规范不同公司版本的统一操作

缓存一致性协议(MESI)

当多个cpu从主内存读取同一个数据到各自的高速缓存

一旦开启了MESI,某个工作内存中修改完的值立马同步到主内存中!

  1. 也就是马上进行store和write原子操作,将这个工作内存的值赋值给主内存!
  2. 打开cpu总线嗅探机制。开启所有CPU对总线的嗅探。关注总线对应副本的值一旦嗅探到它发生了改变,原本的值将进入失效状态。
  3. 重新从主内存中进行read和load操作,读取新的值给副本。

Volatile可见性底层实现原理

Intel 64对lock指令的描述

变量加了volatile后,读取到该变量时,会通过lock指令锁定这个变量的缓存行,(1)并立即写回到主内存中,同时(2)开启缓存一致性协议。

汇编的lock前缀指令

volatile保证可见性与有序性

指令重排序与内存屏障

可见性

可见性:就是保证了不同cpu中工作内存的缓存副本之间共享变量的可见性,一旦修改就能使其它缓存副本读取到,线程之间的可见性。

发生指令重排序,导致出现不同的结果

as-if-serial与happens-before原则

 

阿里面试题:双重检测锁DCL对象半初始化问题

通过两层检测+一把锁的方式保证对象的单例模式的实例化。

第一层检测 判断:if(instance==null){…} 如果对象instance!=null,则直接返回一个instance对象,如果instance==null,就进第二层。

第二层:锁+检测  使用synchronized保证线程的安全性,让线程依次进入里面的代码块,也就是第二层检测,同样是if(instance==null){…},为什么要加第二层检测?因为在第一次没有实例出对象时,可能会有多个线程满足第一层检测而进入到第二层,由于synchronized的原因进行排队进入第二层检测,如果不加第二层检测if(instance==null){…},那些进入第二层排队的线程都将产生新对象,违背了单例模式。正是因为有了第二层检测,第一个线程通过第二层检测产生instance对象,这时候instance就是不为空,所有排队的线程都会返回同一个instance对象。

对象半初始化,由于在单线程执行时没有违背as-if-serial与happens-before原则,也就是指令发生重排序对单线程执行的结果不影响也不发生错误,(也就是说对自己本身的线程结果不影响,但是会影响别人)但是!在并发编程中就会影响其它线程对它的取值,会造成对象半初始化问题!例如在user的构造方法里做一些赋值操作,这个值在其它线程由于指令重排序导致发生变化导致在user的构造方法里无法读取新的值,就会导致产生的user没有完全是按代码顺序执行的结果。

cpu本身不会为了分析各线程之间的依赖关系,而导致复杂度的提升和性能的严重损耗。

 

但是以上代码是一个阿里巴巴开发手册里的一个反例,需要加一个volatile,解决指令重排问题。

 

 

 

 

 

 

 

通过一个类new一个对象出来后,首先会判断该类是否被类加载器加载,若是没有加载就进行加载,加载完后,jvm的栈会给对象分配出一块内存来,接下来就是进行初始化,初始化的过程是给对象赋一个默认值,比如对于i=6 就会先赋一个0给i,i=0;init方法是c语言实现的,为了给变量赋值的i=6。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值