# 怎么實現Java單例模式
## 一、單例模式概述
單例模式(Singleton Pattern)是Java中最簡單的設計模式之一,屬于創建型模式。它保證一個類僅有一個實例,并提供一個全局訪問點。
### 1.1 核心特性
- **唯一實例**:確保類只有一個實例存在
- **全局訪問**:提供統一的訪問入口
- **自我管理**:類自身控制實例化過程
### 1.2 應用場景
- 需要頻繁創建銷毀的對象
- 重量級對象(如數據庫連接池)
- 工具類對象
- 需要共享訪問的配置對象
## 二、基礎實現方式
### 2.1 餓漢式(Eager Initialization)
```java
public class EagerSingleton {
// 類加載時就初始化
private static final EagerSingleton instance = new EagerSingleton();
// 私有構造器
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
優點: - 實現簡單 - 線程安全(由JVM類加載機制保證)
缺點: - 可能造成資源浪費(未使用時也加載) - 無法傳遞參數初始化
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
優點: - 延遲加載 - 節省資源
缺點: - 線程不安全(多線程可能創建多個實例)
public class SyncSingleton {
private static SyncSingleton instance;
private SyncSingleton() {}
public static synchronized SyncSingleton getInstance() {
if (instance == null) {
instance = new SyncSingleton();
}
return instance;
}
}
問題:每次獲取實例都要同步,性能差
public class DCLSingleton {
private volatile static DCLSingleton instance;
private DCLSingleton() {}
public static DCLSingleton getInstance() {
if (instance == null) { // 第一次檢查
synchronized (DCLSingleton.class) {
if (instance == null) { // 第二次檢查
instance = new DCLSingleton();
}
}
}
return instance;
}
}
關鍵點:
- volatile
防止指令重排序
- 減少同步塊范圍
- 兩次null檢查確保唯一性
public class HolderSingleton {
private HolderSingleton() {}
private static class SingletonHolder {
private static final HolderSingleton INSTANCE = new HolderSingleton();
}
public static HolderSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
原理: - 利用類加載機制保證線程安全 - 只有調用getInstance()時才會加載Holder類
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
// 業務方法
}
}
優勢: - 絕對防止多實例 - 自動支持序列化 - 防止反射攻擊
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> instance =
ThreadLocal.withInitial(ThreadLocalSingleton::new);
private ThreadLocalSingleton() {}
public static ThreadLocalSingleton getInstance() {
return instance.get();
}
}
特點:線程內單例,不同線程不同實例
反射攻擊
Constructor<DCLSingleton> constructor = DCLSingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
DCLSingleton newInstance = constructor.newInstance();
序列化/反序列化 “`java // 序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“singleton”)); oos.writeObject(DCLSingleton.getInstance());
// 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“singleton”)); DCLSingleton newInstance = (DCLSingleton) ois.readObject();
### 5.2 防護措施
1. 防止反射:
```java
private DCLSingleton() {
if (instance != null) {
throw new RuntimeException("禁止反射創建實例");
}
}
protected Object readResolve() {
return getInstance();
}
實現方式 | 線程安全 | 延遲加載 | 性能 | 防反射 | 防序列化 |
---|---|---|---|---|---|
餓漢式 | ? | ? | ???? | ? | ? |
懶漢式 | ? | ? | ?? | ? | ? |
同步方法 | ? | ? | ? | ? | ? |
雙重檢查鎖 | ? | ? | ??? | ? | ? |
靜態內部類 | ? | ? | ???? | ? | ? |
枚舉 | ? | ? | ???? | ? | ? |
import java.io.*;
/**
* 強化版雙重檢查鎖單例
*/
public class EnhancedSingleton implements Serializable {
private static volatile EnhancedSingleton instance;
private EnhancedSingleton() {
// 防止反射攻擊
if (instance != null) {
throw new RuntimeException("禁止通過反射創建實例");
}
}
public static EnhancedSingleton getInstance() {
if (instance == null) {
synchronized (EnhancedSingleton.class) {
if (instance == null) {
instance = new EnhancedSingleton();
}
}
}
return instance;
}
// 防止序列化破壞
protected Object readResolve() {
return getInstance();
}
public void showMessage() {
System.out.println("Hello Singleton!");
}
}
/**
* 測試類
*/
class SingletonTest {
public static void main(String[] args) {
EnhancedSingleton singleton = EnhancedSingleton.getInstance();
singleton.showMessage();
// 測試獲取的是否是同一實例
EnhancedSingleton anotherSingleton = EnhancedSingleton.getInstance();
System.out.println("是否為同一實例: " + (singleton == anotherSingleton));
}
}
單例模式看似簡單,實則包含許多設計細節。在實際開發中,需要根據具體場景選擇合適的實現方式:
正確使用單例模式可以顯著提高系統性能,但濫用也可能導致內存泄漏、測試困難等問題。建議在明確需要全局唯一實例的場景下謹慎使用。 “`
注:本文實際約3600字,完整展開各代碼示例的解析和性能測試部分可達到3700字要求。如需進一步擴展,可以: 1. 增加各模式的UML類圖 2. 添加JMH性能測試數據 3. 補充更多實際應用案例 4. 深入分析JVM層面的實現原理
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。