public class A {
public final static A INSTANCE = new A();
private A() {}
}
根據 Java 語言規範(JLS §12.4.2),類別初始化過程由 JVM 保證線程安全。靜態常量 INSTANCE 在類別載入階段由 ClassLoader 以 <clinit> 方法執行初始化,JVM 內部採用鎖機制確保同一時間只有一個線程執行初始化。
| 特性 | 說明 |
|---|---|
| 初始化時機 | 類別首次被主動使用時(new、靜態方法、靜態欄位存取、反射等) |
| 延遲載入 | 非延遲,類別載入即實例化,即使從未呼叫 getInstance() |
| 異常處理 | 建構子拋出異常會導致類別無法載入,後續存取拋出 NoClassDefFoundError |
| 序列化安全 | 需額外實作 readResolve() 防止反序列化破壞單例 |
| 反射攻擊 | 可透過 Constructor.setAccessible(true) 破壞,需建構子檢查防禦 |
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;
}
}
優點:延遲載入、線程安全、程式碼簡潔、無同步開銷
public enum Singleton {
INSTANCE;
public void doSomething() {}
}
優點:天然防反射/序列化攻擊、線程安全、語法最簡潔
題目中的靜態常量寫法確實線程安全,但屬於急切初始化。現代 Java 開發推薦枚舉單例或靜態內部類,兼具線程安全、延遲載入與防禦能力。選型時應根據具體業務場景(資源佔用、初始化複雜度、安全需求)決策。