一个程序执行后,会在内存中开辟一块内存空间,cpu会去读取内存中的指令,但是cpu的速度是内存的100倍,因此厂商在优化cpu上做了很多尝试,比如指令重排序,增加缓存等。我们先讲缓存部分。
经过不断的工业尝试,现在主流是三级缓存架构。他们之间的时间差异如下图
而每个缓存里面又是由缓存行组成的。就像下面这样。
每个缓存行大小是64字节,太大影响单次取值的效率,太小频繁切换也耗性能,64是个折中取值。当多线程情况下(多数问题都是在多线程中才会发生),不同线程修改互相独立的变量时,如果这些变量存在同一个缓存行中,那么他们就会发生竞争关系,影响性能。因为一个线程改了一个值,为了保持线程可见性,需要通知其他线程重新去内存去取值。所以这种现象也称之为伪共享。
做个实验:
一般耗时3000毫秒左右。
我们在这段代码的 long x 前加上
再执行代码结果耗时要减少一半以上。
why?
因为一个缓存行是64字节,我们这里设置x 为8字节,启动两个线程,这时候产生了伪共享。而在x 前加上7个long,则补齐了64个字节,就不产生伪共享了。
在java 8之后官方提供了解决方案,@sun.misc.Contended ,使得解决伪共享变得简单了。但是要设置jvm参数才能生效