在軟體開發中,某些物件全系統只需一個實例(如線程池、快取、配置物件)。單例模式確保類只有一個實例,並提供全域訪問點。
public class Singleton {
private static Singleton singleInstance;
private Singleton() {}
public static Singleton getInstance() {
if (singleInstance == null) {
singleInstance = new Singleton();
}
return singleInstance;
}
}
優點:延遲載入,用到才建立。
缺點:線程不安全,多線程並發時可能建立多個實例。
public static synchronized Singleton getInstance() {
if (singleInstance == null) {
singleInstance = new Singleton();
}
return singleInstance;
}
優點:線程安全。
缺點:效率低,每次獲取都要同步,實例建立後其實不需要鎖。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return instance; }
}
優點:JVM 類載入機制天然保證線程安全,調用效率高。
缺點:無延遲載入,類載入即建立,可能造成資源浪費;類較大時拖慢啟動。
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次檢查
synchronized (Singleton.class) { // 加鎖
if (instance == null) { // 第二次檢查
instance = new Singleton();
}
}
}
return instance;
}
}
關鍵點:
volatile 禁止指令重排序,確保構造完成前不可見public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() { return Holder.INSTANCE; }
}
優點:
getInstance() 才載入 Holder 類)若系統存在多個 ClassLoader,同一個類可能被載入多次,導致多個單例實例。解決:指定統一的類載入器載入單例類。
| 寫法 | 線程安全 | 延遲載入 | 效能 | 推薦度 |
|---|---|---|---|---|
| 懶漢式基礎版 | ❌ | ✅ | 高 | ❌ |
| 同步方法 | ✅ | ✅ | 低 | ❌ |
| 餓漢式 | ✅ | ❌ | 高 | 一般 |
| 雙重檢查鎖 | ✅ | ✅ | 高 | ✅ 推薦 |
| 靜態內部類 | ✅ | ✅ | 高 | ✅ 最推薦 |