Java - Singleton 類別

你好,未來的Java大師!今天,我們將深入Java編程中最引人入勝的概念之一:Singleton 類別。如果你是編程新手,別擔心;我會一步一步地引導你,就像這些年來我對無數學生所做的一樣。所以,拿起你喜歡的飲料,放鬆一下,讓我們一起踏上這個令人興奮的冒險旅程!

Java - Singleton Class

Singleton 類別是什麼?

想像你是一家非常獨特的俱樂部的經理。這家俱樂部如此獨特,以至於全世界只能有一個實例。這基本上就是Java中的Singleton類別——一個只允許創建自身的一個實例的類別。

為什麼使用Singleton?

你可能會想,"我們為什麼要限制自己只創建一個實例呢?" 事實上,有幾個原因:

  1. 全局訪問點:它提供了一個訪問特定實例的單一點,使得在應用程序中維護全局狀態變得容易。
  2. 延遲初始化:實例只在需要時創建,節省資源。
  3. 線程安全:當正確實現時,它可以線程安全,即使在多線程環境中也只允許一個實例。

現在,讓我們看看如何在Java中創建一個Singleton類別。

創建Singleton類別

有許多方法可以創建Singleton類別,但我們先從最簡單也是最常見的方法開始:急切初始化。

public class EagerSingleton {
// 私有靜態類別實例
private static final EagerSingleton instance = new EagerSingleton();

// 私有構造器以防止實例化
private EagerSingleton() {}

// 公共靜態方法以返回實例
public static EagerSingleton getInstance() {
return instance;
}
}

讓我們分解一下:

  1. 我們聲明一個私有的靜態最終變量 instance,它是類型的類別。這是將存在的唯一實例。
  2. 構造器是私有的,阻止其他類別創建新實例。
  3. 我們提供一個公共靜態方法 getInstance(),它返回單一實例。

要使用這個Singleton:

EagerSingleton singleton = EagerSingleton.getInstance();

簡單吧?但如果我們想要在需要時才創建實例呢?這就是延遲初始化的用處。

延遲初始化

public class LazySingleton {
private static LazySingleton instance;

private LazySingleton() {}

public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}

在這個版本中,實例只在第一次調用 getInstance() 時創建。然而,這不是線程安全的。在多線程環境中,我們可能會創建多個實例。讓我們來修復這個問題!

線程安全的Singleton

public class ThreadSafeSingleton {
private static ThreadSafeSingleton instance;

private ThreadSafeSingleton() {}

public static synchronized ThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
return instance;
}
}

通過在 getInstance() 方法中添加 synchronized 關鍵字,我們確保只有一個線程可以一次執行這個方法。然而,同步是昂貴的,我們只需要在第一次創建實例時使用它。這時,雙重檢查鎖定模式就派上用場了!

雙重檢查鎖定

public class DoubleCheckedSingleton {
private static volatile DoubleCheckedSingleton instance;

private DoubleCheckedSingleton() {}

public static DoubleCheckedSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedSingleton();
}
}
}
return instance;
}
}

這種模式檢查兩次null:一次不鎖定,一次鎖定。volatile 關鍵字確保多個線程能夠正確地處理 instance 變量。

Bill Pugh Singleton 實現

現在,讓我與你分享我最喜歡的Singleton實現方式,這是以其創造者命名的:Bill Pugh:

public class BillPughSingleton {
private BillPughSingleton() {}

private static class SingletonHelper {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}

public static BillPughSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}

這種方法使用一個靜態內部類別來保存實例。它在不使用同步的情況下線程安全,並在 getInstance() 首次被調用时惰性加載實例。

當使用Singleton

Singletons 非常適合:

  1. 管理共享資源(如數據庫連接)
  2. 協調系統範圍的操作
  3. 管理資源池(如線程池)

然而,請謹慎使用!過度使用Singletons會使你的代碼更難以測試和維護。

Singleton 方法

這裡是一個你可能會在Singleton類別中找到的常用方法表:

方法 描述
getInstance() 返回類別的單一實例
readResolve() 用於序列化以保留Singleton屬性
clone() 通常抛出 CloneNotSupportedException 以阻止克隆

結論

我們今天涵蓋了很多內容。從理解Singleton是什麼,到實現各種類型的Singleton,你現在已經為了在Java項目中使用這個強大的設計模式做好了準備。

記住,就像我們開始時談論的那家獨特俱樂部一樣,Singleton應該謹慎使用。它是一個強大的工具,但隨著权力的增強,責任也越大!

在你繼續你的Java之旅時,你會遇到更多引人入勝的概念。持續編程,持續學習,最重要的是,享受樂趣!也許有一天,你會成為教導下一代程序员關於Singleton及其他概念的導師。

直到下次見,快樂編程!

Credits: Image by storyset