指令重排的理解

指令重排的前提:

1、单线程中执行结果如果一致,那么可以任意交换。
2、语句之间没有依赖关系,那么可以交换。

指令重排的原因:

为了提高执行效率。
理解:
        a=1;
        a++;
        b=2;
    a=1这条指令相当于我发一个请求给内存,然后内存将1这个值返回给a。可以拆解为两步。那么当我发送请求给内存,内存还没有返回数据给我的时候,这个时候,我是处于等待的状态的。那我是不是可以去执行其他的操作,比如b=2;然后当内存将1返回给我的时候,我才完成a=1的操作。然后再执行a++。这样执行的顺序就是b=2;a=1;a++;得到的结果跟a=1;a++;b=2;完全一致。但是指令重排后,JVM的运行效率提高了。

案例1:

Thread one = new Thread(() -> {
	a = 1;
	x = 2;
});

这种情况下,a和x并没有依赖关系,且无论如何交换得到的结果都是一致的。因此可能会先执行x=2,再执行a=1。


案例2:
Thread one = new Thread(() -> {
	a = 1;
	a++;
});

这种情况下,a=1与a++存在依赖关系,则不会发生指令重排。


案例3:

public class Test {
    private static int x = 0, y = 0;
    private static int a = 0, b = 0;
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; ; i++) {
            x = 0; y = 0;
            a = 0; b = 0;
            Thread one = new Thread(() -> {
                a = 1;
                x = b;
            });
            Thread other = new Thread(() -> {
                b = 1;
                y = a;
            });
            one.start(); other.start();;
            one.join(); other.join();
            if (x == 0 && y == 0) {
                String result = "第" + i + "次(" + x + ", " + y + ")";
                System.out.println(result);
            }
        }
    }

}

因为线程one中,a和x并不存在依赖关系,因此可能会先执行x=b;而这个时候,b=0。因此x会被赋值为0,而a=1这条语句还没有被执行的时候,线程other先执行了y=a这条语句,这个时候a还是a=0;因此y被赋值为了0。所以存在情况x=0;y=0。这就是指令重排导致的多线程问题。

解决方法:
我们可以采用volatile修饰,防止指令重排。这个时候,永远不会存在x=0,y=0的情况。

public class Test {
    private volatile static int x = 0, y = 0;
    private volatile static int a = 0, b = 0;
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; ; i++) {
            x = 0; y = 0;
            a = 0; b = 0;
            Thread one = new Thread(() -> {
                a = 1;
                x = b;
            });
            Thread other = new Thread(() -> {
                b = 1;
                y = a;
            });
            one.start(); other.start();;
            one.join(); other.join();
            if (x == 0 && y == 0) {
                String result = "第" + i + "次(" + x + ", " + y + ")";
                System.out.println(result);
            }
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值