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

什么是指令重排?

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

as-if-serial语义

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

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

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

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

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

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

这个示例里,两个线程无论谁先执行,m和n都不可能都为0,如果出现了,就代表发生了指令重排
复制代码
public class SysParamEnumController {

    int a = 0;
    int b = 0;
    int m = 0;
    int n = 0;

    public static void main(String[] args) throws InterruptedException {

        SysParamEnumController sysParamEnumController = new SysParamEnumController();

        while (true){
            Thread t1 = new Thread(() -> {
                sysParamEnumController.a = 1;
                sysParamEnumController.m = sysParamEnumController.b;
            });

            Thread t2 = new Thread(() -> {
                sysParamEnumController.b = 2;
                sysParamEnumController.n = sysParamEnumController.a;
            });

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

            if (sysParamEnumController.m == 0 && sysParamEnumController.n == 0) {
                System.out.println("m和n都为0,代表出现了指令重排");
                break;
            }

            sysParamEnumController.a = 0;
            sysParamEnumController.b = 0;
            sysParamEnumController.m = 0;
            sysParamEnumController.n = 0;
        }

    }

}
复制代码

 

结果

循环结束就代表受到了指令重排的影响,因为指令重排只会小概率出现,所以每次跑的时间都会不一样。

 如何避免指令重排?

使用内存屏障(volatile)或临界区(synchronized)

对应代码实现分别是给a和b加上volatile

volatile int a = 0;
volatile int b = 0;

volatile的规则

1、第一个操作是volatile读时,第二个无论什么操作都不能重排
2、第二个操作是volatile写时,第一个无论什么操作都不能重排
3、第一个操作是volatile写时,第二个是volatile读时不能重排

或者给两个线程里的逻辑加上synchronized

posted @   夏威夷8080  阅读(126)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2017-07-27 设计模式之状态模式学习理解
2017-07-27 java并发之ReentrantLock学习理解
2017-07-27 java并发之读写锁ReentrantReadWriteLock的使用
点击右上角即可分享
微信分享提示