彻底搞清楚什么是伪共享
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; }
}
小草
专注人工智能、前沿科技领域报道,致力于为读者带来最新、最深度的科技资讯。