jmm乱序问题

一 点睛

cpu的读等待,同时指令执行。

cpu乱序执行的根源:https://www.cnblogs.com/liushaodong/p/4777308.html

读指令的同时,可以同时执行不影响其他指令。

而写的同时可以进行合并写。

这样CPU执行就是乱序的。

必须使用 Memory Barrier 来做好指令排序。

volatile 底层就是这么实现的(windows是lock指令)

CPU为了提高指令执行效率,会在一条指令执行过程中(比如去内存读数据(慢100倍)),去同时执行另外一条指令,前提是,两条指令没有依赖关系。

写操作也可以合并进行。

二 生活中的例子

三 实战

1 代码

package jmm;

public final class WriteCombiningExt {
    private static final int    ITERATIONS = Integer.MAX_VALUE;
    private static final int    ITEMS      = 1 << 24;
    private static final int    MASK       = ITEMS - 1;

    private static final byte[] array1     = new byte[ITEMS];
    private static final byte[] array2     = new byte[ITEMS];
    private static final byte[] array3     = new byte[ITEMS];
    private static final byte[] array4     = new byte[ITEMS];
    private static final byte[] array5     = new byte[ITEMS];
    private static final byte[] array6     = new byte[ITEMS];
    private static final byte[] array7     = new byte[ITEMS];
    private static final byte[] array8     = new byte[ITEMS];
    private static final byte[] array9     = new byte[ITEMS];
    private static final byte[] array10     = new byte[ITEMS];
    private static final byte[] array11     = new byte[ITEMS];
    private static final byte[] array12     = new byte[ITEMS];
    private static final byte[] array13     = new byte[ITEMS];
    private static final byte[] array14     = new byte[ITEMS];

    public static void main(final String[] args) {
        for (int i = 1; i <= 3; i++) {
            System.out.println(i + " SingleLoop duration (ns) = " + runCaseOne());
            System.out.println(i + " SplitLoop  duration (ns) = " + runCaseTwo());
        }
    }
    
        // 循环中一次写
    public static long runCaseOne() {
        long start = System.nanoTime();
        int i = ITERATIONS;
        while (--i != 0) {
            int slot = i & MASK;
            byte b = (byte) i;
            array1[slot] = b;
            array2[slot] = b;
            array3[slot] = b;
            array4[slot] = b;
            array5[slot] = b;
            array6[slot] = b;
            array7[slot] = b;
            array8[slot] = b;
            array9[slot] = b;
            array10[slot] = b;
            array11[slot] = b;
            array12[slot] = b;
            array13[slot] = b;
            array14[slot] = b;
        }
        return System.nanoTime() - start;
    }

    // 分两次循环写
    public static long runCaseTwo() {
        long start = System.nanoTime();
        int i = ITERATIONS;
        while (--i != 0) {
            int slot = i & MASK;
            byte b = (byte) i;
            array1[slot] = b;
            array2[slot] = b;
            array3[slot] = b;
            array4[slot] = b;
            array5[slot] = b;
            array6[slot] = b;
            array7[slot] = b;
        }
        i = ITERATIONS;
        while (--i != 0) {
            int slot = i & MASK;
            byte b = (byte) i;
            array8[slot] = b;
            array9[slot] = b;
            array10[slot] = b;
            array11[slot] = b;
            array12[slot] = b;
            array13[slot] = b;
            array14[slot] = b;
        }
        return System.nanoTime() - start;
    }
}

2 测试环境

3 测试结果

SingleLoop duration (ns) = 19421047700

SplitLoop  duration (ns) = 11710882200

4 说明

分两次循环写的性能优于循环中一次写,这处决于机器的 WC Buffer的个数。

不同机器的WC Buffer个数是不一样的,一般都是4个,但从测试来看,笔者的机器是8个。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值