Java多线程环境下可能会出现指令重排的代码示例

夏威夷8080 / 2023-07-27 / 原文

什么是指令重排?

我们在执行程序时,为了提高性能,编译器和处理器某些情况下会对指令进行重排序。

as-if-serial语义

不管怎么重排序,不能影响单线程环境下的执行结果,这是as-if-serial语义定义的,编译器和处理器阶段的重排都遵循该规则。

编译器和处理器都遵循的指令重排的原则

a、数据依赖,只对不存在数据依赖的指令进行重排。

b、控制依赖,允许对有控制依赖关系的指令做重排。

Java多线程环境下可能会出现指令重排的代码示例

既然有了上面两个指令重排的前提,我们就可以根据这些规则写一个demo来实际测验出指令重排。

public class SysParamEnumController {

    private volatile int a = 0;
    private volatile int b = 0;
    private volatile boolean flag = false;

    // 此方法里的三个指令没有数据依赖关系
    public void write() {
        a = 1;
        b = 2;
        flag = true;
    }
    // 此方法里的if就是控制依赖关系
    public void render() {
        if (flag) {
            System.out.println(a * b);
        } else {
            System.out.println("-1");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 1000; i++) {
            SysParamEnumController sysParamEnumController = new SysParamEnumController();
            Thread t1 = new Thread(() -> {
                sysParamEnumController.write();
            });

            Thread t2 = new Thread(() -> {
                sysParamEnumController.render();
            });

            t1.start();
            t2.start();
            t1.join();
            t2.join();
        }


    }
}

结果

出现了-1就代表受到了指令重排的影响,因为指令重排只会小概率出现,所以我循环了1000次。