Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android設計模式之單例模式 Singleton

Android設計模式之單例模式 Singleton

編輯:關於Android編程

一.概述

 

單例模式是設計模式中最簡單的一種,但是它沒有設計模式中的那種各種對象之間的抽象關系,所以有人不認為它是一種模式,而是一種實現技巧.單例模式就像字面的意思一樣,提供一個只能自己實例化的實例,並且提供了一個全局的訪問點.要達到這幾點要求就要滿足三點:私有構造函數(防止被別人實例化),靜態私有自身對象(用來提供實例),靜態公有的getInstance方法(用來創建和獲取實例對象).
優缺點: 單例只允許自己建立一個實例,不需要頻繁創建和銷毀,可以節省內存加快對象的訪問速度. 但是單例沒有抽象層和借口,不方便擴展.單例既提供工廠方法又提供業務方法,一定程度上違背了單一職責原則

二.單例實現

單例的實現有兩個主流方式,分別是懶漢模式和餓漢模式,他們在實例化的時機和效率方面各有不同

 

1.懶漢模式

 

/**
 * Created by jesse on 15-6-28.
 */
public class Singleton {
    private static Singleton instance;
    private Singleton() {} //一定要有私有構造,要不談何單例
    public static Singleton getInstance(){
        if (null == instance){
            instance = new Singleton();
        }
        return instance;
    }
}

 

 

懶漢模式在外部對象每次獲取實例時都要先判斷該實例是否被初始化,這點相比餓漢模式來說就會損失一些效率,但是會節省一些空間,因為什麼時候用到該實例才會去初始化,如果一直用不到的話,在懶漢模式裡面時不會構造該對象的.相當於用空間換時間.也就是延遲加載技術.還有一點需要注意的是一定要有私有構造,要不然外部對象還是可以實例化該對象,那還談何單例.

 

這個時候很多小伙伴要說了,你這個懶漢單例有問題,有線程安全問題.當然這個方式是線程不安全的,當兩個線程A和B並發要獲取實例的時候,instance還沒有被初始化,假設A先拿到時間片去初始化instance,當instance還沒有初始化完成的時候,時間片讓給了B,這時由於instance還沒有被初始化完成那麼instance還為空,所以B還會去把instance實例化一次,最終的結果就是instance被實例化了兩次.這可能會造成很嚴重的後果,解決方式就是加鎖(犧牲一些性能),使用餓漢模式.

 

給getInstance方法加鎖,這種加鎖方式可以解決線程安全問題,但是每次外部對象要獲取實例的時候都要進行線程鎖定,之後還要再判斷instance是否被實例化了,這樣在多線程高並發的情況下效率損失就很可觀了.

 

public class Singleton {
    private static Singleton instance;
    private Singleton() {} 
    public static synchronized Singleton getInstance(){//給getInstance方法加鎖
        if (null == instance){
            instance = new Singleton();
        }
        return instance;
    }
}

後來又延伸出了一種雙檢鎖實例的方式,這種方式只在第一次實例化的時候進行加鎖,並在在加鎖前後都會對是否實例化了進行判定.性能方面優於單檢鎖的形式.但是這種雙檢鎖還會遇到一個問題,就是在不同的平台或不同的編譯器下可能出現錯誤.主要是因為有些編譯器優化了new Singleton()的過程,假設線程AB並發獲取實例,在有些編譯器下可能會出現A線程實例化instance的過程中,當系統已經給instance分配到內存,但是還沒有初始化instance的成員變量的時候,時間片讓給了B進程,這時候instance已經不為null了,B就直接拿著實例去操作成員變量,但是這個時候成員變量還沒有被初始化,結果就可能crash了.當遇到這種編譯器問題的時候就需要給instance變量加上volatile修飾,去除編譯器優化的干擾.

 

public class Singleton {
    private static Singleton instance;
    //private static volatile Singleton instance; 遇到編譯器問題時使用
    private Singleton() {}
    public static Singleton getInstance(){
        if (null == instance){
            synchronized(Singleton.class){
                if (null == instance)
                    instance = new Singleton();
            }

        }
        return instance;
    }
}

 

 

2.餓漢模式

 

餓漢模式是在系統運行起來,在裝在類的時候就進行初始化的操作,外部對象使用的時候不需要做任何判斷可以直接使用,從效率上來說是優於懶漢模式的.但是對比懶漢模式的延遲加載技術,不管系統用不用該實例,內存都會在最開始的時候創建出來.跟懶漢的時間換空間正好相反,餓漢是空間換時間.

 

public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton() {}//一定要有私有構造,要不談何單例
    public static Singleton getInstance(){
        return instance;
    }
}

 

三.總結


根據上面的分析可以很清楚的了解到:餓漢模式不用面對對線程並發的問題.並且從調用速度和響應時間來說餓漢模式要優於懶漢模式.但是從資源利用的角度來說懶漢模式要優於餓漢模式.
 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved