伪共享以及如何避免

CPU在向内存发起IO操作的时候,一次性会读取64个字节的数据作为一个缓存行,缓存到CPU的高速缓存里面, 在Java中一个long类型是8个字节,意味着一个缓存行可以存储8个long类型的变量

由于存放到CPU缓存行的是内存块而不是单个变量,所以可能会把多个变量存放到 同一个缓存行 中, 当多个线程同时修改这个缓存行里面的多个变量时,由于同时只能有一个线程操作缓存行, 此时有两个线程同时修改同一个缓存行下的两个不同的变量,这就是伪共享

当出现伪共享时,CPU必须清空该级缓存行,会造成CPU比较大的开销。一旦运行在某个CPU上的线程获得了所有权并执行了修改,就会导致其他CPU中的缓存行失效。

这个问题的解决办法有两个:

  • 使用对齐填充,因为一个缓存行大小是64个字节,如果读取的目标数据小于64个字节,可以增加一些无意义的成员变量来填充。

  • 在Java8里面,提供了@Contented注解,它也是通过缓存行填充来解决伪共享问题的,被@Contented注解声明的类或者字段,会被加载到独立的缓存行上。

在默认情况下,@Contended 注解只用于 Java 核心类, 比如rt包下的类
如果用户类路径下的类需要使用这个注解, 需要添加JVM 参数:- XX:-RestrictContended。 填充的宽度默认为 128 ,要自定义填充宽度则可以通过参数 -XX:ContendedPaddingWidth 参数进行设置。

在Netty里面,有大量用到对齐填充的方式来避免伪共享问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值