單例的四種實現方式


一、什么是單例模式?

1、定義

Singleton模式要求一個類有且僅有一個實例,並且提供了一個全局的訪問點。這就提出了一個問題:如何繞過常規的構造器,提供一種機制來保證一個類只有一個實例?客戶程序在調用某一個類時,它是不會考慮這個類是否只能有一個實例等問題的,所以,這應該是類設計者的責任,而不是類使用者的責任。

從另一個角度來說,Singleton模式其實也是一種職責型模式。因為我們創建了一個對象,這個對象扮演了獨一無二的角色,在這個單獨的對象實例中,它集中了它所屬類的所有權力,同時它也肩負了行使這種權力的職責

2、單例模式的優點

1)在單例模式中,活動的單例只有一個實例,對單例類的所有實例化得到的都是相同的一個實例。這樣就 防止其它對象對自己的實例化,確保所有的對象都訪問一個實例

2)單例模式具有一定的伸縮性,類自己來控制實例化進程,類就在改變實例化進程上有相應的伸縮性。

3)提供了對唯一實例的受控訪問。

4)由於在系統內存中只存在一個對象,因此可以 節約系統資源,當 需要頻繁創建和銷毀的對象時單例模式 無疑可以提高系統的性能。

5)允許可變數目的實例。

6)避免對共享資源的多重占用。

3、單例模式的應用場景

單例模式只允許創建一個對象,因此節省內存,加快對象訪問速度,因此對象需要被公用的場合適合使用,如多個模塊使用同一個數據源連接對象等等。如:

1)需要頻繁實例化然后銷毀的對象。

2)創建對象時耗時過多或者耗資源過多,但又經常用到的對象。

3)有狀態的工具類對象。

4)頻繁訪問數據庫或文件的對象。

以下都是單例模式的經典使用場景:

1)資源共享的情況下,避免由於資源操作時導致的性能或損耗等。如上述中的日志文件,應用配置。

2)控制資源的情況下,方便資源之間的互相通信。如線程池等

二、單例的四種實現方式

1、餓漢式

餓漢式: 在類裝載的時候就急速的初始化,餓漢式是線程安全的、 但是沒有延遲加載


/**
 * 餓漢式
 */
class Singleton_one {

    // 1、私有化構造器
    private Singleton_one() {
    }

    // 2、初始化
    private static Singleton_one instance = new Singleton_one();

    public static Singleton_one getInstance() {
        return instance;
    }
}

2、懶漢式(同步方法)

單純的懶漢式是存在線程安全問題的、需要我們使用同步策略

/**
 * 懶漢式(同步方法)
 */
class Singleton_two {

    // 1、私有化構造器
    private Singleton_two() {
    }

    private static Singleton_two instance = null;

    public synchronized static Singleton_two getInstance() {

        if (instance == null) {
            instance = new Singleton_two();
        }
        return instance;
    }
}

3、懶漢式(Dubbo Check)

單純的懶漢式是存在線程安全問題的、需要我們使用同步策略、這里使用了雙重校驗

/**
 * 懶漢式(Double Check)
 */
class Singleton_three {

    // 私有化構造器
    private Singleton_three() {
    }

    private static Singleton_three instance = null;

    public static Singleton_three getInstance() {

        if (instance == null) {

            synchronized (Singleton_three.class) {

                if (instance == null) {
                    instance = new Singleton_three();
                }
            }
        }
        return instance;
    }
}

4、靜態內部類

1)靜態內部類的加載時機

  1. 外部類初次加載,會初始化靜態變量、靜態代碼塊、靜態方法,但不會加載內部類和靜態內部類。
  2. 實例化外部類,調用外部類的靜態方法、靜態變量,則外部類必須先進行加載,但只加載一次。
  3. 直接調用靜態內部類時,外部類不會加載。
/**
 * 內部類實現單例模式
 * <p>
 * 既不用加鎖 、也能實現懶加載
 *
 *
 * 外部類初次加載的時候不會加載內部類和靜態內部類
 */
class Singleton_four {

    private static int a = 10;

    // 私有化構造器
    private Singleton_four() {
    }

    private static class Inner {

        static Singleton_four instance = new Singleton_four();
    }

    public static Singleton_four getInstance() {
        return Inner.instance;
    }
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com