java并发编程(7)-final属性的内存语义

JMM 规定的final属性的重排序规则
1)在构造函数内对一个final属性的写入,与随后把这个执行构造方法构造的对象的引用赋值给一个变量 这两个操作不能重排序。就是说一定是先执行 final属性的写入,然后才能通过引用访问构造(new)的对象。
注意这里只保证了final属性的写入顺序,没有保证普通属性的顺序(就是说普通属性的写可能会被重排序到构造方法外执行)。
2)第一次读去一个包含final属性的实例的引用,与随后读取final属性这两个操作不能重排序。就是说肯定是先读到实例的引用,然后才会去读final属性值
在这里插入图片描述
final语义的实现方式

很显然 先拿到一个对象的引用 再去访问对象中的属性 ,这两个操作是有关联的。大部分处理器不会对有关联关系的两条指令进行重排序,所以在大部分的处理器中JMM其实不用做任何操作。就能保证这一点。而且一旦这两个指令重排序了,那访问的结果肯定是错误的。 对于不能自动禁止这种重排序的,JMM必须在final读取对象引用 操作和 读取final属性操作之间加 load load 屏障。同理对于不能自动禁止final写重排序的处理器,需要在构造方法中的final写入操作之后 构造方法返回前,插入 store store 屏障。
疑问 一旦加了storestore 屏障那么 构造方法中所有的写都不会重排序到构造方法外,但是规则描述中却说普通属性的写入可能被重排序到构造方法外?为啥?
在这里插入图片描述

包含final属性的对象引用不能从构造函数中“溢出”
简单来说就是 如果要保证上述语义的正确,就必须遵守不要在构造方法中将正在被创建的对象的引用,传递出去。示例如下图。原因也简单,一旦在构造方法中做了这个操作那么,其他线程就可以在构造方法没有执行完的情况下对对象及其属性进行访问,可能访问的时候属性还未正确赋值。这样就肯定会出问题了。

在这里插入图片描述
JSR-133为什么要增强final的语义

在旧的java内存模型中一个问题就是,线程可以看到final的值会改变。比如 final属性被写入前实际保存的值时默认值 比如0。写入后的值为A 。那么由于CPU可能将final写入重排序到构造方法外,线程可能会读到默认值0 ,然后再次读取又读取到修改后的值A .
为了修补这个漏洞,JSR-133 专家组增强了final的语义。只要对象是正确构造的(对象引用没有在构造方法中外溢)那么不需要线程同步,就可以看到final被初始化后的值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catch that elf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值