java 编译器重排序_关于java 指令重排序的一些理解

参考《java编程之美》

public class Test {

public static class ReadThread extends Thread {

public void run() {

while (!Thread.currentThread().isInterrupted()) {

if (ready) {

System.out.println(num + num);

}

System.out.println("read is over");

}

}

}

public static class WriteThread extends Thread {

public void run() {

num = 2;

ready = true;

System.out.println("write thread is over");

}

}

private static int num = 0;

private static boolean ready = false;

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

ReadThread rt = new ReadThread();

rt.start();

WriteThread wt = new WriteThread();

wt.start();

Thread.sleep(10);

rt.interrupt();

System.out.println("main is over");

}

}

上面有3个线程,一个主线程,一个读线程,一个写线程。读写线程之间并没有什么先后顺序。开启两个线程后,线程处于就绪状态,等待cpu调度。

然后主线程sleep10ms.目的是让读写线程充分执行结束。最后调用读线程的中断方法使读线程中断结束。

然后大家可以先自己揣摩结果是啥。

我刚开始看感觉没看懂,自己没理解。后面理解了,所以在这里记下笔记。

先来说说什么事java指令重排序:

java内存模型允许编译器和处理器对指令重排序以提高运行性能,并且只会对不存在数据依赖性的指令重排序。

然后我们先来了解数据依赖性:

int a=1;

int b=2;

int c=a+b;

这里由于变量c的值依赖于a和b的值,所以不会进行重排序,即不会变成:

int c=a+b;

int a=1;

int b=2;

这样的顺序。

然后再来看最前面的程序:

if (ready) {

System.out.println(num + num);

}

num = 2;

ready = true;

由于在两个线程中,所以这上面三个步骤是没有数据依赖性的。

所以在写线程中,它不一定会执行num=2后再让ready=true;

有可能会ready=true后再运行num=2;

如果是后面这种情况的话,读线程就可能先读到ready为true,然后默认num=0,所以直接输出0+0=0;然后cpu又继续运行num=2;此时会再输出2+2=4的这种情况。

所以,这就是指令重排序带来的灾难。

但是,你们运行上面的程序估计很难运行出0的情况,因为带有很大的不确定性。所以自己理解了就好。

java为了避免发生这种情况,可以使用volatile修饰上面的ready,这样ready前面的操作比如num=2就不会被重排序到ready后面。这样就不会发生前面的这种情况。

写volatile变量时,可以确保volatile写之前的操作不会被编译器重排序到volatile写之后。读volatile变量时,可以确保volatile读之后的操作不会被编译器重排序到volatile读之前。

上面就是我理解到的指令重排序。

欢迎交流讨论。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值