计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排,一般分为以下三种
- 单线程环境里面确保程序最终执行结果和代码顺序执行的结果一致
- 处理器在进行重排序时必须考虑指令之间的数据依赖性
- 多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果无法预测
代码demo如下
public class ReSortSeqDemo {
int a = 0;
boolean flag = false;
public void method01() {
//多线程环境下 语句1和语句2可能会出现指令重排,然后另一个线程可能执行method02方法
a = 1; //语句1
flag = true; //语句2
}
//多线程环境中线程交替执行,犹豫便一起优化重排的存在,
// 两个线程中使用的变量能否保证一致性是无法确定的,结果无法进行预测
public void method02() {
if (flag) {
a = a + 5;//语句3
}
}
}
volatile实现禁止指令重排优化,从而避免多线程环境下程序出现乱序执行的现象
先了解一个概念,内存屏障(Memory Barrier) 又称内存栅栏,是一个CPU指令,它的作用有两个:
一是保证特定操作的执行顺序,
二是保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)
由于编译器和处理器都能执行指令重排优化。如果在指令间插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化。内存屏障另外一个作用就是强制刷出各种CPU的缓存数据,因此任何CPU上的线程都能读取到这些数据的罪行版本。
总结:
- 工作内存与主内存同步延迟现象导致的可见性问题
- 可以使用synchronized或volatile关键字解决,他们都可以是一个线程修改后的变量立刻对其他线程可见
- 对于指令重排导致的可见性问题和有序性问题
- 可以利用volatile关键字解决,因为volatile的另外一个作用就是禁止重排序优化