面試問題
1.在多線程情況下的Singleton寫法
// version 1.4
public class Singleton {
private volatile static Singleton singleton = null;
private Singleton() { }
public static Singleton getInstance() {
if (singleton == null ) {
synchronized(Singleton.class) {
if (singleton == null ) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
使用 volatile 有兩個功用:
1)這個變量不會在多個線程中存在復本器仗,直接從內存讀取渴逻。
2)這個關鍵字會禁止指令重排序優(yōu)化乍赫。也就是說匆篓,在 volatile 變量的賦值操作后面會有一個內存屏障(生成的匯編代碼上)暂吉,讀操作不會被重排序到內存屏障之前胖秒。
但是,這個事情僅在Java 1.5版后有用慕的,1.5版之前用這個變量也有問題阎肝,因為老版本的Java的內存模型是有缺陷的。
// version 1.6
// ref: <<Effective Java>>
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton () { }
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
上面這種方式肮街,仍然使用JVM 本身機制保證了線程安全問題风题; 由于SingletonHolder是私有的,除了
getInstance() 之外沒有辦法訪問它嫉父,因此它只有在getInstance() 被調用時才會真正創(chuàng)建沛硅;同時讀取實例的時候不會進行同步,沒有性能缺陷绕辖;也不依賴jdk 版本摇肌。
Singleton 優(yōu)雅版本
public enum Singleton {
INSTANCE;
}
居然用枚舉!仪际!看上去好牛围小,通過EasySingleton.INSTANCE來訪問,這比調用getInstance()方法簡單多了树碱。
默認枚舉實例的創(chuàng)建是線程安全的肯适,所以不需要擔心線程安全的問題。但是在枚舉中的其他任何方法的線程安全由程序員自己負責成榜。還有防止上面的通過反射機制調用私用構造器框舔。
Reference
深入淺出單實例Singleton設計模式 | 酷殼 - CoolShell.cn