getInstance()| 方案 | 線程安全 | 延遲加載 | 性能 | 推薦度 |
|---|---|---|---|---|
| 懶漢式 + synchronized 方法 | ✅ | ✅ | ❌ 每次調用加鎖 | ⭐ |
| 雙重檢查鎖 (DCL) + volatile | ✅ | ✅ | ✅ 首次加鎖,後續無鎖 | ⭐⭐⭐⭐ |
| 靜態內部類 | ✅ | ✅ | ✅ 類加載機制天然保證 | ⭐⭐⭐⭐⭐ |
| 枚舉 | ✅ | ❌ (類加載時創建) | ✅ 極簡 | ⭐⭐⭐⭐⭐ |
| 餓漢式 | ✅ | ❌ | ✅ | ⭐⭐⭐ |
public final class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
Holder 類只在首次調用 getInstance() 時被加載、初始化readResolve)public enum Singleton {
INSTANCE;
// 可添加字段、方法
public void doSomething() { ... }
}
public final class Singleton {
private volatile static Singleton instance; // 關鍵:volatile 禁止指令重排
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次檢查(無鎖)
synchronized (Singleton.class) { // 類級別鎖
if (instance == null) { // 第二次檢查(有鎖)
instance = new Singleton(); // 實例化
}
}
}
return instance;
}
}
instance = new Singleton() 非原子操作:
JVM 可能重排為 1→3→2,導致另一線程看到 instance != null 但對象未初始化完成。volatile 禁止重排,保證可見性與有序性。
private static final Lock lock = new ReentrantLock();
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
lock.lock();
try {
if (instance == null) instance = new Singleton();
} finally {
lock.unlock();
}
}
return instance;
}
語義清晰,但比 synchronized 繁瑣,且無 JVM 優化(偏向鎖、輕量級鎖)。
// ❌ 錯誤示範:每次調用返回新實例!
public static synchronized Singleton getInstance() {
if (instance == null) instance = new Singleton();
return new Singleton(); // Bug: 應返回 instance
}
// 靜態內部類 / DCL 補強
private Singleton() {
if (Holder.INSTANCE != null) // 或 instance != null
throw new IllegalStateException("單例已存在");
}
// 防序列化
protected Object readResolve() {
return getInstance(); // 反序列化時返回唯一實例
}
枚舉天然免疫上述攻擊。
@Scope("singleton"),容器管理切記:單例不是萬能的,高併發下可能成為瓶頸,考慮無狀態設計或 ThreadLocal/對象池替代。