3 有序性(Ordering)
乱序问题
- 即程序不顺序执行。
- 为什么允许乱序情况?主要是为了提升CPU效率。
- 乱序存在条件:不影响单线程的最终一致性,即前后指令没有依赖关系
- 下面程序的问题?
- 可见性问题:ready未用volatile修饰,可能导致死循环;
- 有序性问题:number输出可能为0。
public class NoVisibility {
private static boolean ready = false;
private static int number;
private static class ReaderThread extends Thread {
@Override
public void run() {
while(!ready) {
Thread.yield();
}
System.out.printly(number);
}
}
public static void main(String[] args) throws Exception {
Thread t = new ReaderThread();
t.start();
number = 42;
ready = true;
t.join();
}
}
对象的半初始化状态
- 对象的创建过程
- new申请内存,此时对象中的属性基本数据类型引用类型都是默认值(此时就是半初始化状态)—— 默认值;
- 特殊调用(汇编码)invokespecial ** <T.>class的构造方法之后,再初始化成员变量,按照给定的代码赋值 —— 初始值;
- astore_1建立变量和对象之间的关联——关联。
Jclasslib插件 -> 查看汇编码
- this对象溢出
- 汇编码中4,7句可能交换顺序;
- 不要在构造方法里面启动一个线程。
哪些指令可以互换顺序?
暂略
如何阻止乱序执行?
- 内存屏障:它是特殊的指令,看到这种指令,及必须等前面执行完,后面才能执行。
- intel:Ifence sfence mfence(CPU特有指令)
- JVM中的内存屏障:
a. LoadLoad屏障
b. StoreStore屏障
c. LoadStore屏障
d. StoreLoad屏障
// Load 读指令
// Store 写指令
// Load1 和 Load2 不允许换顺序
Load1
LoadLoad
Load2
- volatile 禁止重排序:
a. 等别人Store完,我才能Store
b. 等我Store完,别人才能Load
- 等我Load完,别人才能Load
- 等我Load完,别人才能Store
Note:
volatile 两大功能:维持可见性和有序性