Java設計模式之幾種常見的單例模式的寫法及優缺點比較

概述

今天再來總結一篇開發中常用的設計模式單例模式,其定義是單例對象的類只能允許一個實例存在,它雖然有多種常見的寫法,但是其基本思想不變:

  1. 構造器私有化,使外部無法無法new 對象
  2. 提供一個獲取對象的方法 即提供一個get方法獲取第三部中的屬性,但是要求所有對象共用故而用static修飾
  3. 內部提供一個實例 作爲屬性 要求私有化 靜態化 private static

單例模式幾種常見的寫法

1:餓漢模式

  1. 優點:寫法比較簡單、線程安全,在類加載的時候就完成實例化。
  2. 缺點:在類加載的時候就完成實例化,沒有達到Lazy Loading(懶加載)的效果。如果從始至終從未使用過這個實例,則會造成內存的浪費。
public class SingleInstance {
    //餓漢模式線程安全
    //step1 :私有化構造器
    private SingleInstance() {
    }
    //step2 :提供私有化靜態屬性
    private static SingleInstance sSingleInstance = new SingleInstance();
    //step3 : 通過獲取該屬性的方法
    public static SingleInstance getInstance() {
        return sSingleInstance;
    }
}

2:懶漢模式

  1. 優點:這種方式實現了Lazy Loading的效果,單線程提可保證單例
  2. 缺點:線程不安全,只適用於單線程不適用於多線程
public class SingleInstance {
    //懶漢模式
    //step1 :私有化構造器
    private SingleInstance(){}
    //step2 :提供私有化靜態屬性
    private static SingleInstance sInstance;
    //step3 : 通過獲取該屬性的方法
    public static SingleInstance getInstance(){
        if (sInstance == null) {
            sInstance=new SingleInstance();
        }
        return sInstance;
    }
}

3:懶漢模式:同步方法

通過synchronized 修飾該方法,保證線程安全

  1. 優點:實現了懶加載,並且線程安全
  2. 缺點:效率低不推薦使用,因爲使用了synchronized修飾方法,每次使用時都得同步
public class SingleInstance {
    //懶漢模式 同步方法
    //step1 :私有化構造器
    private SingleInstance(){}
    //step2 :提供私有化靜態屬性
    private static  SingleInstance sInstance;
    //step3 : 通過獲取該屬性的方法  synchronized修飾該方法
    public static synchronized SingleInstance getInstance(){
        if (sInstance == null) {
            sInstance=new SingleInstance();
        }
        return sInstance;
    }
}

4:懶漢模式:同步代碼塊

通過synchronized 修飾該方法,保證線程安全

  1. 優點:實現了懶加載,
  2. 缺點:線程不安全,和方法二一樣不適用於多線程,不推薦使用

public class SingleInstance {
    //懶漢模式  同步代碼快
    //step1 :私有化構造器
    private SingleInstance(){}
    //step2 :提供私有化靜態屬性
    private static  SingleInstance sInstance;
    //step3 : 通過獲取該屬性的方法  synchronized修飾該方法
    public static  SingleInstance getInstance(){
        if (sInstance == null) {
            synchronized (SingleInstance.class){
                sInstance=new SingleInstance();
            }
        }
        return sInstance;
    }
}

5:雙重鎖機制(推薦)

優點:實現了懶加載,線程安全,效率高,第一層判null提高了鎖機制的使用效率,第二層判null纔是真正意義的單例。

public class SingleInstance {
    //雙重鎖
    //step1 :私有化構造器
    private SingleInstance(){}
    //step2 :提供私有化靜態屬性
    private static  SingleInstance sInstance;
    //step3 : 通過獲取該屬性的方法  synchronized修飾該方法
    public static  SingleInstance getInstance(){
        if (sInstance == null) {//第一層:保證的多線程只有第一次調用getInstance 的時候纔會加鎖初始化
            synchronized (SingleInstance.class){
                if (sInstance==null) {// 第二層 實現了單例模式
                    sInstance=new SingleInstance();
                }
            }
        }
        return sInstance;
    }

6:靜態內部類(推薦)

優點:避免了線程不安全,延遲加載,效率高。

public class SingleInstance {
    //靜態內部類
    //step1 :私有化構造器
    private SingleInstance(){}
    //step2 :提供私有化靜態屬性
    private static  SingleInstance sInstance;
    //step3 : 通過獲取該屬性的方法  synchronized修飾該方法
    public static  SingleInstance getInstance(){
        //只有調用此方法的時候纔會初始化單例,實現了懶加載,因爲類(Single)的加載只有一次,從而保證了單例
        return Single.sInstance;
    }

    private static class Single{
        private static SingleInstance sInstance=new SingleInstance();

    }
}

這種方式跟餓漢式方式採用的機制類似,但又有不同。兩者都是採用了類裝載的機制來保證初始化實例時只有一個線程。不同的地方在餓漢式方式是隻要Singleton類被裝載就會實例化,沒有Lazy-Loading的作用,而靜態內部類方式在Singleton類被裝載時並不會立即實例化,而是在需要實例化時,調用getInstance方法,纔會裝載SingletonInstance類,從而完成Singleton的實例化。

類的靜態屬性只會在第一次加載類的時候初始化,所以在這裏,JVM幫助我們保證了線程的安全性,在類進行初始化時,別的線程是無法進入的。

單例模式的優缺點以及使用場景

優點: 系統內存中該類只存在一個對象,節省了系統資源,對於一些需要頻繁創建銷燬的對象,使用單例模式可以提高系統性能。

優點:
系統內存中該類只存在一個對象,節省了系統資源,對於一些需要頻繁創建銷燬的對象,使用單例模式可以提高系統性能。

缺點:
單例類的職責過重,在一定程度上違背了“單一職責原則”。

適用場景:

  1. 工具類對象;
  2. 需要頻繁的進行創建和銷燬的對象,並且創建對象時耗時過多或耗費資源過多,如:訪問I0和數據庫等資源或者有很多個地方都用到了這個實例。
  3. 頻繁訪問數據庫或文件的對象,
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章