徹底明白Android設計模式—單例模式

這次講講最簡單也最常用的單例模式(顧名思義 保證實例唯一的一種設計模式)

直接五種單例模式獻上,讓你瞭解單例模式的前世今生

餓漢模式

像一個餓漢一樣,不管需不需要,有沒有,都一定要去創建實例。因爲太餓了,不管三七二十一,我就要吃!!!

	/*一、餓漢模式*/
    private static Singleton singleton = new Singleton();

    public static Singleton getSingleton() {
        return singleton;
    }

餓漢模式是在類初始化的時候就創建了實例,所以不管用不用都創建了實例,但是是線程安全的,因爲靜態變量的創建,在類的初始化過程中是保證線程安全的。

  • 優點:線程安全,讀取變量速度快
  • 缺點:因爲一開始就創建了變量,如果後面沒用到,就有可能浪費資源

懶漢模式 (不考慮線程安全)

像一個懶漢一樣,需要的時候纔去實例化,不需要我就不實例化。

    /*二、懶漢模式-線程不安全模式*/
    private static Singleton singleton2;

    public static Singleton getSingleton2() {
        if (singleton2 == null) {
            singleton2 = new Singleton();
        }
        return singleton2;
    }
  • 優點:需要的時候纔會實例化變量,實現懶加載
  • 缺點:線程不安全

懶漢模式 (線程安全)

這種較上面升級了一點,就是考慮到線程安全,當兩個線程同時操作怎麼辦,肯定要加鎖啦

    /* 三、懶漢模式-線程安全模式
     * 增加synchronized實現實例同步
     * */
    private static Singleton singleton3;

    public synchronized static Singleton getSingleton3() {
        if (singleton3 == null) {
            singleton3 = new Singleton();
        }
        return singleton3;
    }

synchronized修飾符保證同一時間只有一個線程能進入該方法

  • 優點:線程安全,懶加載
  • 缺點:需要每次都走鎖的部分,性能不算很好

雙重加鎖

這種就是我們代碼中常用的啦,雙重加鎖的同時,用volatile修飾變量

	private volatile static Singleton singleton4;

    public static Singleton getSingleton4() {
        if (singleton4 == null) {
            synchronized (Singleton.class) {
                if (singleton4 == null) {
                    singleton4 = new Singleton();
                }
            }

        }
        return singleton4;
    }

這種模式在保證線程安全的同時提高了性能:

  • synchronized加鎖使得同一時間只有一個線程能進入

  • 外面又加了一層if判斷其實就是爲了性能,如果不爲空就不需要進入下面鎖的部分了,直接返回

  • volatile修飾符爲了讓singleton4實例在變化後立即寫入主存,方便其他線程讀取,否則有可能造成空指針,因爲new的過程不是一瞬間的,所以有可能在操作過程中,另一個線程讀到singleton4還是空的。

  • 優點:線程安全,懶加載,性能也還可以

  • 缺點:有點複雜,可能加載速度不快

靜態內部類模式-號稱最優雅單例

這種方法精髓就在於比較優雅,代碼量少,簡單易懂。
第一次調用方法時候,纔會去加載SingletonHolder內部類並且實例化INSTANCE

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getSingleton5() {
        return SingletonHolder.INSTANCE;
    }

ok,你說只會存在一個實例我是看到了,但是這個爲啥就能保證線程安全了呢?

這就要說到類的初始化了,類初始化階段是類加載過程的最後一步,也是執行類構造器()方法的過程。
而虛擬機會保證一個類的()方法在多線程環境中被正確地加鎖和同步。如果有多個線程去同時初始化一個類,那麼只會有一個線程去執行這個類的()方法,其它線程都需要阻塞等待,直到活動線程執行()方法完畢。
所以,明白了吧,內部類在初始化過程中是線程安全的,所以就能保證這個單例的創建也是線程安全的。

  • 優點:線程安全,懶加載,代碼量少,簡單易懂
  • 缺點:在調用getSingleton5方法不能帶上參數進行實例化,比如上下文參數Context

在Android中的應用

應該隨處可見吧,當某個實例在app中被多次調用,就需要創建一個單例,不讓其多次創建。
一般就選用雙重加鎖或者靜態內部類模式即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章