编译指令 :javac Test.java
反编译指令: javap -v Test
代码
public class ObjectTest {
int m = 8;
public static void main(String[] args) {
ObjectTest o = new ObjectTest();
}
}
安装jclasslib插件后,可以看到这个类的clazz文件: 如图所示:
这个是 对象的创建过程, 这个过程中有个半初始化状态, 这里的 invokespecial 和 astore_1 这二条指令会发生指令重排,
比如一个 双重检查的单例模式:
class Singleton {
private Singleton() {
}
private volatile static Singleton INSTANCE;//这里没有使用 volatile 关键字
public static Singleton getInstance() {
if (INSTANCE == null) { //第1行
synchronized (Singleton.class) { //第2行
if (INSTANCE == null) { //第三行
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton(); //第四行
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread(()->{System.out.println(Singleton.getInstance().hashCode());}).start();
}
}
}
如果 没有volatile关键字,那么在 INSTANCE = new Singleton();这一行代码,new对象的时候,对应的clazz文件的 invokespecial 和 astore_1 这二条指令就有可能会发生指令重排,
先new了对象,此时对象创建处于半初始状态, 先执行了astore_1 建立了关联,后执行了 invokespecial, 就会导致, 第一行判断INSTANCE == null, 此时加锁,接下来判断 INSTANCE 为半初始化状态,并不为null, 那么这个单例模式就会失败
所以 这种双重检查的单例模式, volatile关键字不能少