volatile是否存在伪共享问题?

1.什么是伪共享和共享?

        在探讨LongAdder是如何解决伪共享问题之前,我们要先梳理清一个概念,什么是伪共享和共享?

        共享在Java编程里面我们可以这样理解,有一个Share类,它有一个value的属性。如下:

public class Share{
    int value;
}

        我们初始化Share的一个实例,然后启动多个线程去操作它的value属性,此时的Share变量被多个线程操作的这种情况我们称之为共享。

        大家都知道在不添加任何互斥措施的情况,多线程操作这个Share变量的value属性肯定存在线程安全性的问题。那有什么办法可以解决这个问题呢?我们可以使用volatile和CAS技术来保证共享变量可以安全的被多个线程共享操作使用,不知道volatile和CAS技术点的同学可以参考往期文章ReentranLock实现原理居然是这样?。

        但是由于volatile的引入,会带来一些问题。大家都知道JMM(Java内存模型)规范了volatile具有内存可见性和禁止指令重排序的语义。这俩条语义使得某个线程更新本地缓存中的value值后会将其他线程的本地缓存中的value值失效,然后其他线程再次读取value值的时候需要去主存里面获取value值,这样即保证了value的内存可见性。

        当然啦,这没有任何问题,但是由于线程本地缓存的操作是以缓存行为单位的,一个缓存行大小通常为64B(不同型号的电脑缓存行大小会有不同)。因此一个缓存行中不会只单单存储value一个变量,可能还会存储其他变量。这样当一个线程更新了value之后,如果其他线程本地缓存中同样缓存了value,value所在的缓存行就会失效,这意味着该缓存行上的其他变量也会失效,那么线程对这个该缓存行上所有变量的访问都需要从主存中获取。我们都知道CPU访问主存的速度相对于访问缓存的速度有着数量级的差距,这就带了很大的性能问题,我们将这个问题称之为伪共享。

        理解了伪共享到底是什么鬼以后,我们来看看Java大师们是怎么解决这个问题的。在早期版本的JDK里面你应该见到过类似如下的代码:

public class Share{
    volatile int value;
    long p1,p2,p3,p4,p5,p6;
}

        你可能猜到了,定义了几个无用的变量作为填充物,他们会保证一个缓存行里面只保存了Share变量,这样更新Share变量的时候就不会存在伪共享问题了。但是这种方法存在什么问题呢?

        首先基于每台运行Java程序的机器的缓存行大小可能不同,其次由于这些类似填充物的变量并没有被实际使用,可以被JVM优化掉,这样就失效了。

        基于此,在Java8的时候,官方给出了手机号码拍卖解决策略,这就是Contended注解。依赖于这个注解,我们在Java8环境下可以这样改善代码:

public class Share{
    @Contended
    volatile int value;
}

        使用如上注解,并且在JVM启动参数中加入-XX:-RestrictContended,这样JVM在运行时就会自动的为我们的Share类添加合适大小的填充物(padding)来解决伪共享问题,而不需要我们手写变量来作为填充物了,这样就更加便捷优雅的解决了伪共享问题。悄悄的告诉你,LongAdder就是使用Contended来解决伪共享问题哒。

        好了,相信你已经了解了什么是伪共享问题,以及早期并发编程大师是如何解决伪共享问题的,最后我们也介绍了在Java8中使用Contended来更优雅的解决伪共享问题。Contended还提供了一个缓存行分组的功能,在上文中我们没有介绍,欢迎有兴趣的小伙伴们自行探索吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

会飞的IT蜗牛

更美口味,打赏人生

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

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

打赏作者

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

抵扣说明:

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

余额充值