單例模式的6種實現(xiàn)方式

為什么使用單例模式

需要確保某個類只要一個對象,或創(chuàng)建一個類需要消耗的資源過多,如訪問IO數(shù)據(jù)庫操作等,這時就需要考慮使用單例模式了。

使用單例模式需要注意的關(guān)鍵點

  1. 將構(gòu)造函數(shù)訪問修飾符設(shè)置為private
  2. 通過一個靜態(tài)方法或者枚舉返回單例類對象
  3. 確保單例類的對象有且只有一個,特別是在多線程環(huán)境下
  4. 確保單例類對象在反序列化時不會重新構(gòu)建對象

單例模式的幾種寫法

1. 餓漢式

/**
 * 餓漢式實現(xiàn)單例模式
 */
public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
    }

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

2. 懶漢式

/**
 * 懶漢式實現(xiàn)單例模式
 */
public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    // synchronized方法,多線程情況下保證單例對象唯一
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

getInstance()方法中添加了synchronized關(guān)鍵字,使其變成一個同步方法,目的是為了在多線程環(huán)境下保證單例對象唯一。

優(yōu)點: 只有在使用時才會實例化單例,一定程度上節(jié)約了資源。
缺點: 第一次加載時要立即實例化,反應(yīng)稍慢。每次調(diào)用getInstance()方法都會進行同步,這樣會消耗不必要的資源這種模式一般不建議使用。

3. DCL(Double CheckLock)實現(xiàn)單例

/**
 * DCL實現(xiàn)單例模式
 */
public class Singleton {
    private static Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        // 兩層判空,第一層是為了避免不必要的同步
        // 第二層是為了在null的情況下創(chuàng)建實例
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }

        }
        return instance;
    }
}

優(yōu)點: 資源利用率高,既能夠在需要的時候才初始化實例,又能保證線程安全,同時調(diào)用getInstance()方法不進行同步鎖,效率高。
缺點: 第一次加載時稍慢,由于Java內(nèi)存模型的原因偶爾會失敗。在高并發(fā)環(huán)境下也有一定的缺陷,雖然發(fā)生概率很小。
DCL模式是使用最多的單例模式實現(xiàn)方式,除非代碼在并發(fā)場景比較復(fù)雜或者JDK 6以下版本使用,否則,這種方式基本都能滿足需求。

4. 靜態(tài)內(nèi)部類

/**
 * 靜態(tài)內(nèi)部類實現(xiàn)單例模式
 */
public class Singleton {
    private Singleton() {
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }

    /**
     * 靜態(tài)內(nèi)部類
     */
    private static class SingletonHolder {
        private static Singleton instance = new Singleton();
    }
}

第一次加載Singleton類時不會初始化instance,只有在第一次調(diào)用getInstance()方法時,虛擬機會加載SingletonHolder類,初始化instance。

這種方式既保證線程安全,單例對象的唯一,也延遲了單例的初始化,推薦使用這種方式來實現(xiàn)單例模式。

5. 枚舉單例

/**
 * 枚舉實現(xiàn)單例模式
 */
public enum SingletonEnum {
    INSTANCE;
    public void doSomething() {
        System.out.println("do something");
    }
}

默認枚舉實例的創(chuàng)建是線程安全的,即使反序列化也不會生成新的實例,任何情況下都是一個單例

優(yōu)點: 簡單!

6. 容器實現(xiàn)單例

import java.util.HashMap;
import java.util.Map;
/**
 * 容器類實現(xiàn)單例模式
 */
public class SingletonManager {
    private static Map<String, Object> objMap = new HashMap<String, Object>();

    public static void regsiterService(String key, Object instance) {
        if (!objMap.containsKey(key)) {
            objMap.put(key, instance);
        }
    }

    public static Object getService(String key) {
        return objMap.get(key);
    }
}

SingletonManager可以管理多個單例類型,使用時根據(jù)key獲取對象對應(yīng)類型的對象。這種方式可以通過統(tǒng)一的接口獲取操作,隱藏了具體實現(xiàn),降低了耦合度。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容