初探JMM

什么是内存模型

在多CPU的系统中,每个CPU都有多级缓存,在这种情况下如果两个CPU同时操作一个内存地址会发生什么?在什么条件下 ,它们可以看到相同的结果?

所以内存模型保证其他CPU的写入动作对该CPU是可见的,而且该CPU的写入动作对其他CPU也是可见的。

对于有些处理器,提供了弱内存模型,需要执行特殊的指令(barriers内存屏障),刷新CPU缓存的数据到内存中,保证这个写操作对其它CPU可见,或者将CPU缓存的数据设置为无效状态,保证其他CPU的写操作对本CPU可见。

内存屏障的作用除了实现CPU间的数据可见性之外,还有禁止指令重排的的功能。

例如,编译器认为把某个变量的写操作放在最后会更有效,那么编译器会在不改变语义的情况下将这个写操作放到最后,如果真的放到了最后,那么在执行之前,另一条线程将不会看到这个执行结果。

再例如,写入的操作也有可能会被移动到前面,那么带来的影响是是,其它线程可能会在程序实现“发生”之前,看到这个写入动作,显然这可能会带来某些问题。

通过内存屏障,可以禁止一些不必要或者会带来负面影响的重拍优化,在内存模型的范围内,实现更高的性能,同时保证程序正确。

synchronized可以做什么

synchronized有多种语义,最熟悉的是互斥。

对于一个monitor对象,只能够被一个线程持有,意味着一旦有线程进入了同步代码块,那么其它线程就不能进入直到第一个进入的线程退出代码块。

其它功能就是,使用synchronized保证了线程在同步块之前或者期间的写入操作,对于后续进入代码块的线程是可见的。

在一个线程退出代码块时,线程释放monitor对象,它的作用是把CPU缓存数据刷新到内存中,从而实现该线程的行为对于其他线程的可见性。

在其它线程进入到该代码块时,需要获取monitor对象,它的作用是使CPU缓存失效,从而使变量从主内存中重新加载,然后就可以看到之前其它线程对变量的修改。

从缓存角度看,synchronized还有一个禁止重排的语义,同步块中的代码不会移动到获取和释放monitor对象外边。

final可以做什么?

如果一个包含final字段,且在构造函数中初始化,那么正确的构造一个对象后,final字段被设置后,此字段对于其它线程是可见的。

volatile可以做什么?

volatile关键字主要是用于线程间的通讯,被volatile关键字修饰的字段的每次读操作都能看到其它线程最后一次对该字段的写操作,通过volatile修饰就可以避免拿到某个变量缓存中的旧数据。

必须保证在写入后,会被刷新到主内存中,这样就可以让其它线程可见。

volatile的内存语义和synchronized释放和获取monitor的实现目的差不多。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值