指令重排序

Posted hongchengshise

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了指令重排序相关的知识,希望对你有一定的参考价值。

在多线程并发编程的过程中,执行重排序有时候会造成错误的后果,比如一个线程在main线程中调用setFlag(true)的前边修改了某些程序配置项,而在t1线程里需要用到这些配置项,所以会造成配置缺失的错误。但是java给我们提供了一些抑制指令重排序的方式。

1.同步代码抑制指令重排序

将需要抑制指令重排序的代码放入同步代码块中:

技术图片

在获取锁的时候,它前边的操作必须已经执行完成,不能和同步代码块重排序;在释放锁的时候,同步代码块中的代码必须全部执行完成,不能和同步代码块后边的代码重排序。

2.volatile变量抑制指令重排序

public class Reordering {

    private static volatile boolean flag;
    private static int num;

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                while (!flag) {
                    Thread.yield();
                }

                System.out.println(num);
            }
        });
        t1.start();
        num = 5;
        flag = true;
    }
}

  

具体抑制重排序的规则如下:

  1. volatile写之前的操作不会被重排序到volatile写之后。

  2. volatile读之后的操作不会被重排序到volatile读之前。

  3. 前边是volatile写,后边是volatile读,这两个操作不能重排序。

3.final变量抑制指令重排序

具体的规则就这两条:

  1. 在构造方法内对一个final字段的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。

  2. 初次读一个包含final字段对象的引用,与随后初次读这个final字段,这两个操作不能重排序。

以上是关于指令重排序的主要内容,如果未能解决你的问题,请参考以下文章

Java 并发编程指令重排序规范 ( happens-before 先行发生原则 )

指令重排序导致的可见性问题

什么是重排序

指令重排序

指令重排序

JUC并发编程 -- 有序性(指令重排序优化 & 支持流水线的处理器 & 指令重排序的问题/验证/禁用)