局部性原理与缓存行

时间局部性:CPU读取数据时的顺序为寄存器->L1->L2->L3->内存,当从内存中读取到数据时,会一次将数据放入L3、L2、L1中,这样下次CPU再读取这个数据时直接从L1中获取,无需读取内存。CPU认为程序在短时间内有多次操作同一个数据的倾向,所以会将数据存储在高速缓存中。

空间局部性:CPU认为从内存中读取一个数据,下一次访问的很有可能是它旁边的数据,所以会进行预读取,目前工业界一次性预读取的大小一般为64Byte,这64个字节的大小一般称为缓冲行,也就是说CPU在读取数据的时候一次性读取一个缓冲行大小。

下面通过一个例子来证明缓冲行的存在:

例1:

package com.morris.concurrent.volatiledemo;

public class CacheLinePadding {

    private static class T {
        public volatile long x = 0L;
    }

    public static T[] arr = new T[2];

    static {
        arr[0] = new T();
        arr[1] = new T();
    }

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            for (long i = 0; i < 1000_0000L; i++) {
                arr[0].x = i;
            }
        });

        Thread t2 = new Thread(() -> {
            for (long i = 0; i < 1000_0000L; i++) {
                arr[1].x = i;
            }
        });

        final long start = System.nanoTime();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println((System.nanoTime() - start) / 1_000_000);
    }
}

例2:将例1中的T类换成下面的,其余保持不变:

private static class T {
    public volatile long p1, p2, p3, p4, p5, p6, p7;
    public volatile long x = 0L;
    public volatile long p8, p9, p10, p11, p12, p13, p14;
}

运行结果如下:

12710ms
例21270ms

运行结果原因分析:

例1:arr[0].x与arr[1].x很大可能位于同一个缓存行中,这样多个核内的高速缓存中都有arr[0].x和arr[1].x的副本,当线程t1对arr[0].x进行修改时会使得其他核内的缓存行失效,导致其他线程每次对数据的操作需要从先从内存中读取,没有充分利用高速缓存,影响性能。
例2:变量x的前后被填充了7个long型变量,也就是前后填充了56个字节,加上x自身总共64个字节,而缓存行的大小为64个字节,这样就保证了arr[0].x与arr[1].x一定不会在同一个缓存行,当线程t1和线程t2分别对这样arr[0].x与arr[1].x进行写操作时,无需使用缓存一致性协议来保证数据的一致性,充分利用了高速缓存,所以性能有所提升。
jdk提供了@sun.misc.Contended注解来实现缓存行对齐,无需手动填充变量了,在运行时需要设置JVM启动参数-XX:-RestrictContended,使用方法如下:

private static class T {
    @sun.misc.Contended
    public volatile long x = 0L;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值