| 模式 | 線程安全 | 延遲加載 | 性能 | 防反射/序列化 | 推薦指數 |
|---|---|---|---|---|---|
| 餓漢式 (靜態常量) | ✅ 類加載時初始化 | ❌ | 極高 | 需額外處理 | ⭐⭐⭐ |
| 餓漢式 (靜態代碼塊) | ✅ | ❌ | 極高 | 需額外處理 | ⭐⭐⭐ |
| 懶漢式 (同步方法) | ✅ | ✅ | 低 (鎖粗) | 需額外處理 | ⭐ |
| 懶漢式 (同步代碼塊) | ❌ 無效 | ✅ | 低 | 需額外處理 | ❌ |
| 雙重檢查鎖 (DCL) | ✅ (需 volatile) | ✅ | 高 | 需額外處理 | ⭐⭐⭐⭐ |
| 靜態內部類 | ✅ 類加載機制保證 | ✅ | 高 | 需額外處理 | ⭐⭐⭐⭐⭐ |
| 枚舉單例 | ✅ JVM 保證 | ✅ (調用時) | 高 | ✅ 天然防反射/序列化 | ⭐⭐⭐⭐⭐ |
public class HungrySingleton {
private static final HungrySingleton INSTANCE = new HungrySingleton();
private HungrySingleton() {}
public static HungrySingleton getInstance() { return INSTANCE; }
}
public class DclSingleton {
private static volatile DclSingleton instance;
private DclSingleton() {}
public static DclSingleton getInstance() {
if (instance == null) { // 第一次檢查,無鎖
synchronized (DclSingleton.class) { // 加鎖
if (instance == null) { // 第二次檢查
instance = new DclSingleton(); // 實例化
}
}
}
return instance;
}
}
volatile 禁止指令重排序,保證其他線程看到完全初始化的對象。
public class InnerClassSingleton {
private InnerClassSingleton() {}
private static class Holder {
static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance() {
return Holder.INSTANCE;
}
}
利用類加載器初始化靜態內部類時的線程安全特性,兼具延遲加載與高性能。
public enum EnumSingleton {
INSTANCE;
private Connection conn;
EnumSingleton() {
// 初始化資源
}
public Connection getConnection() { return conn; }
}
JVM 保證枚舉常量只實例化一次,天然防反射攻擊(Constructor.newInstance 拋異常)、防序列化破壞(readResolve 不需要)。
實現 Serializable 後,反序列化會創建新對象。修復:
protected Object readResolve() {
return INSTANCE; // 返回現有實例
}
枚舉單例無需此方法。
public class SingletonTest {
public static void main(String[] args) throws InterruptedException {
int threads = 1000;
CountDownLatch latch = new CountDownLatch(threads);
Set<Object> instances = Collections.synchronizedSet(new HashSet<>());
for (int i = 0; i < threads; i++) {
new Thread(() -> {
instances.add(EnumSingleton.INSTANCE); // 替換測試目標
latch.countDown();
}).start();
}
latch.await();
System.out.println("實例數量: " + instances.size()); // 應為 1
}
}
this 或非類對象 → 無效,必須鎖 Class 對象。volatile → 指令重排導致半初始化對象逃逸。