关于指令重排序

为了提高程序执行的性能,编译器和处理器会对指令进行重新排序,但重新排序的一个前提条件是『不能改变程序在单线程状态下执行的结果』。

举个简单的例子:

第一行代码 int a = 10; 和第二行代码 boolean flag = true; 的执行顺序,就可以被『重排序』(这里只是举个例子,不是说编译器就一定会对这两行代码进行重排序),因为这两行代码的执行顺序不会影响最终的变量 result 的结果是 100,在单线程的情况下,这样的重排序是没问题的,因为最终的计算结果是正确的。

但是在多线程的情况下,上述指令重排序就可能会产生问题。

看上面代码,单线程情况下,先调用 init() 方法设置 a = 100; 和 flag = true; ,再调用 run() 方法,init() 方法设置 a = 100; 和 flag = true; 这两行代码的顺序如果发生了重排序(即先执行 flag = true; 再执行 a = 100)也不会影响 run() 方法执行的结果(即 result 最终等于 10000),所以编译器或处理器有可能对这两行代码做重排序。

但是在多线程情况下,上面的重排序就可能产生问题,比如编译器或处理器对 a = 100; 和 flag = true; 进行重排序后变成了先 flag = true; 然后 a = 100; ,那么当线程1 执行了 flag = true; 后失去了 CPU 使用权,线程2 开始执行 run() 方法判断 flag 的值是 true 就执行了 int result = a * a; ,而此时 a = 1,所以最终 result 的结果就是 1 了。

怎么禁止这种重排序呢?我们只用用 volatile 对 flag 变量进行修饰即可,然后针对 flag 变量的操作就会按照你源码中的顺序执行,不会再对其进行重排序。

参我的文章 volatile 关键字详解

完。

码先生
Author: 码先生

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注