單例的四種實現方式

1、什麼是單例模式?

一、定義

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

<!--more-->數據庫

從另外一個角度來講,Singleton模式其實也是一種職責型模式。由於咱們建立了一個對象,這個對象扮演了獨一無二的角色,在這個單獨的對象實例中,它集中了它所屬類的全部權力,同時它也肩負了行使這種權力的職責安全

二、單例模式的優勢

1)在單例模式中,活動的單例只有一個實例,對單例類的全部實例化獲得的都是相同的一個實例。這樣就 防止其它對象對本身的實例化,確保全部的對象都訪問一個實例工具

2)單例模式具備必定的伸縮性,類本身來控制實例化進程,類就在改變實例化進程上有相應的伸縮性。性能

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

4)因爲在系統內存中只存在一個對象,所以能夠 節約系統資源,當 須要頻繁建立和銷燬的對象時單例模式 無疑能夠提升系統的性能。線程

5)容許可變數目的實例。設計

6)避免對共享資源的多重佔用。日誌

三、單例模式的應用場景

單例模式只容許建立一個對象,所以節省內存,加快對象訪問速度,所以對象須要被公用的場合適合使用,如多個模塊使用同一個數據源鏈接對象等等。如:code

1)須要頻繁實例化而後銷燬的對象。

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

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

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

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

1)資源共享的狀況下,避免因爲資源操做時致使的性能或損耗等。如上述中的日誌文件,應用配置。

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

2、單例的四種實現方式

一、餓漢式

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

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

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

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

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

二、懶漢式(同步方法)

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

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

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

    private static Singleton_two instance = null;

    public synchronized static Singleton_two getInstance() {

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

三、懶漢式(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;
    }
}

四、靜態內部類

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;
    }
}
相關文章
相關標籤/搜索