彻底搞清楚什么是伪共享

2024-10-13
77 阅读

1、什么是伪共享?

1.1背景

1.1.1 CPU缓存架构

我们知道CPU的处理速度与内存、硬盘的访问速度有很到的关系,为了缓解CPU处理速度与内存、硬盘的访问速度的差别,在当代的CPU中,普通引入了CPU缓存,那CPU缓存的架构是怎样的,直接上图:

? ? ? ? Thread t2 =new Thread(() -> {

for (int i =0; i <100000000; i++) {

pointer.b++;

? ? ? ? ? ? }

}, "B");

? ? ? ? t1.start();

? ? ? ? t2.start();

? ? ? ? t1.join();

? ? ? ? t2.join();

? ? ? ? System.out.println(System.currentTimeMillis() - start);

? ? ? ? System.out.println(pointer.a +"@" + Thread.currentThread().getName());

? ? ? ? System.out.println(pointer.b +"@" + Thread.currentThread().getName());

? ? }

}

class Pointer {

//在一个缓存行中,先会存储a

? ? volatile long a;

? ? //? ? 放开下面这行,解决伪共享的问题,提供了性能? --- 方法1

? ? long p1, p2, p3, p4, p5, p6, p7;

? ? volatile long b;

}

程序输出:

3370 ? //基本在3000ms多的耗时

100000000@main

100000000@main

1.4解决伪共享的方法

知道了伪共享产生的原理,就不难找到解决伪共享的方法了,总结起来大概有下面三个

1.4.1 在变量的后背凑齐64个字节的变量

如上面的pointer类改成:

classPointer {

??? //在一个缓存行中,先会存储a

volatile long a;?//需要volatile,保证线程间可见并避免重排序//??? 放开下面这行,解决伪共享的问题,提高了性能

? ??long p1, p2, p3, p4, p5, p6, p7;

volatile long b;??//需要volatile,保证线程间可见并避免重排序

}

再运行上面的程序,输出:

1284 ?//基本在1000ms多的耗时,性能提高了2倍

100000000@main

100000000@main

1.4.2 使用消除了伪共享结构的类

如上面的程序不直接使用long类型,我们自动以一个long类型:MyLong

classPointer2{

??? MyLong

a = newMyLong();

??? MyLong b = newMyLong();

}

classMyLong {

volatile longvalue;

??? longp1,p2,p3,p4,p5,p6,p7;

}

让后再简单的改下:

private static void testPointer(Pointer2 pointer)

pointer.a++ 改成 pointer.a.value++

pointer.b++ 改成 pointer.b.value++

再次执行程序,输出:

1285 ?//与不消除伪共享前,性能提高2倍

com.javastack.mtc.cacheline.MyLong@1de0aca6@main

com.javastack.mtc.cacheline.MyLong@255316f2@main

1.4.3 使用jdk8注解:@sun.misc.Contended

修改 MyLong 如下:

@sun.misc.Contended

classMyLong {

????volatile longvalue;

}

或者:

classPointer {

volatile long a;

??? @Contended

volatile long b;

}

@Contended注解使用方法

@Contended 注解会增加目标实例大小,要谨慎使用。默认情况下,除了 JDK 内部的类,JVM 会忽略该注解。要应用代码支持的话,需要在jvm启动参数上设置 -XX:-RestrictContended=false,它默认为 true(意味仅限 JDK 内部的类使用)。当然,也有个 –XX: EnableContented 的配置参数,来控制开启和关闭该注解的功能,默认是 true,如果改为 false,可以减少 Thread 和 ConcurrentHashMap 类的大小。参考《Java性能权威指南》。

1.3 使用了伪共享的大牛例子?

1.3.1 jdk中的ConcurrentHashMap类

@sun.misc.Contended static final class CounterCell {
? ?volatile long value;
? ?CounterCell(long x) { value = x; }
}

分享至:
管理员

小草

专注人工智能、前沿科技领域报道,致力于为读者带来最新、最深度的科技资讯。

评论 (0)

当前用户头像