單例設計模式

LilyFlower發表於2024-10-25

單例設計模式

單例設計模式是一種常見的軟體設計模式,它能保證一個類只能有一個例項,並提供一個全域性訪問的方法。單例設計模式適用於那些需要頻繁建立物件然後銷燬物件的場景,因為頻繁的建立物件會消耗大量的系統資源,使用單例設計模式可以避免對資源的浪費。

單例設計模式特點:

  • 該類在JVM中只有唯一的類例項
  • 它必須對外界提供統一的,獲取該類例項的方法

在Java中,實現單例設計模式分為多種:

  1. 餓漢式:在類載入階段時就建立例項,該模式下不會出現執行緒安全問題,因此並不需要加鎖,如下面的程式碼
public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();

        System.out.println(singleton1);
        System.out.println(singleton2);
    }
}

class Singleton {
    private static final Singleton singleton = new Singleton();
    private Singleton() {}
    public static Singleton getSingleton() {
        return singleton;
    }
}

執行結果如下:

leetcode.Singleton@58372a00
leetcode.Singleton@58372a00
  1. 懶漢式:懶漢式指的是在第一次使用該類例項時才建立該類例項,這種方式的好處是可以延遲載入,缺點是在多執行緒下可能會引起執行緒安全問題,例如建立該類的多個例項,從而違背了單例設計模式的特性。因此在使用懶漢式需要在建立該類例項時需要加上鎖,如下面的程式碼:
public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();

        System.out.println(singleton1);
        System.out.println(singleton2);
    }
}

class Singleton {
    private static Singleton singleton;

    private Singleton() {}

    public synchronized static  Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

程式碼執行結果如下:

leetcode.Singleton@7ba4f24f
leetcode.Singleton@7ba4f24f
  1. 懶漢式2(靜態內部類方式)

當然了,除了上面那種常用的懶漢式建立單例的方法,也可以透過內部類方式透過懶漢式建立單例例項,這種本質上還是懶漢式,如下面的程式碼:

public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();

        System.out.println(singleton1);
        System.out.println(singleton2);
    }
}

class Singleton {

    private static class Builder {
        private static final Singleton singleton = new Singleton();
    }

    private Singleton() {}

    public synchronized static  Singleton getSingleton() {
        return Builder.singleton;
    }
}

執行結果如下:

leetcode.Singleton@3b9a45b3
leetcode.Singleton@3b9a45b3
  1. 透過列舉實現(推薦用法)

列舉本質上就是單例模式的一種體現,其思路也是懶漢式,列舉之所以能夠作為單例,原因如下:

4.1 執行緒安全性:列舉型別的例項化是在JVM層面完成的,因此列舉類例項化是執行緒安全的。當JVM載入列舉類時,JVM會確保所有宣告的列舉類僅初始化一次,並且在這個過程中不會發生併發問題。

4.2 防止反射攻擊:Java列舉類的構造器是私有的,並且Java不允許透過反射機制建立新的列舉示例,這也就意味著一旦定義了一個列舉例項,就無法透過反射以及其它手段建立該列舉類的額外例項。

4.3 程式碼簡潔:列舉的語法非常的簡潔,如下面的程式碼:

public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton2 == singleton1);
    }
}

enum Singleton {
    INSTANCE;
}

相關文章