并发可见性与总线窥探机制

Java中volatile关键字确保变量在多线程环境下的可见性,解决了因CPU缓存不一致带来的问题。总线窥探是缓存一致性的一种解决方案,通过监听总线上的修改操作来保持一致性。MESI协议是缓存一致性协议的示例,管理缓存的状态以维护正确性。文章还提到了伪共享问题,即高速缓存行可能导致未预期的缓存失效,并提供了避免策略,如使用@Contended注解。
摘要由CSDN通过智能技术生成

在java并发编程中,要保证可见性,需要给变量增加volatile关键字。

普通变量存在可见性的原因是多核CPU架构中各处理器缓存不一致造成的,需要解决缓存不一致问题,才能保证可见性,总线窥探就是实现缓存一致性的方案之一。

缓存不一致

1、cpu1和cpu2都读取了x变量

2、cpu1对x变量进行了+100操作, 操作完成后暂时写到缓存中,此时x应该为200.

3、但cpu2的缓存内x仍然是100,产生了缓存不一致问题

4、最终会导致x值不准确,可能是200,也可能还是100。

总线窥探机制 bus snooping

确保缓存一致性的解决方案有两种

总线窥探机制,受制于带宽的限制,只能用于64个核心以内的情况

基于目录的机制,用于大于64个核心的情况

原理

窥探者监视总线每一个修改操作,如果发现了修改操作,就会检查被修改的值是否也同样存在其他缓存内,如果发现了有副本,则使副本失效,然后将被修改的值尽快写回到主存。 那些失效的副本所在处理器,就不得不再去主存重新加载。

窥探协议之一MESI协议

协议存在4个状态,分别为:

M:修改,监测到修改操作时,会对该缓存标记为E,如果其他处理器有该值副本,会被标记为I;

E:独享,只有一个处理器加载了;

S:共享,有多个处理器加载了同一个值,但还没进行写操作;

I:失效,当有E出现时,其他缓存副本会被当失效处理

伪共享问题

高速缓存中,被分为了缓存行(64byte),一次会加载,会将邻近数据也加载,加速cpu操作(局部性原理)。当同一行中的多个变量,在不同的处理器中被修改,会造成全部缓存失效。

在java层面,就是对多个相邻的变量都加了volatile,而且这些变量还被不同的线程使用。

private volatile int a;
private volatile int b;
private volatile int c;
thread1 {
    a=1;
}
thread2 {
    b=2;
}
thread3 {
    c=2;
}

如何避免

自己注意,不要写一大堆volatile在一起,即使写一起,也是共同用于一个事务操作。

或者在volatile变量之间,穿插其他普通变量

增加@Contended注解,需要开启-XX:-RestrictContended

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值