Android設計模式探討--單例模式
核心原則:將建構函式私有化,通過一個靜態內部方法來獲取唯一例項.
單例模式的定義:確保某個類只有一個例項,避免產生多個物件來消耗過度資源。
下面介紹幾種常見實現單例模式的方法。
餓漢模式
它是在宣告該靜態類時該物件已經存在,並且初始化了.
public class Singleton{
private static Singleton mInstance = new Singleton();//注意這裡的static,因為下面呼叫獲取到該例項的是靜態方法.
public static Singleton getInstance() {//靜態方法
return mInstance;
}
private Singleton() {//注意此處的建構函式必須要用private來修飾
}
}
優點:寫的比較簡單,執行緒安全.
缺點:消耗點資源,因為即使你不用該單例,靜態儲存空間中仍然會分配空間給該例項.
懶漢模式
它是懶載入的模式.用的時候載入,不用的時候不佔用空間
public class Singleton{
private static Singleton mInstance;
public static synchronized Singleton getInstance() {//注意這裡必須要加synchronized,否則多執行緒呼叫就會有問題,獲取到不唯一的例項.
if(mInstance == null) {
mInstance =new Singleton();
}
return mInstance;
}
}
優點:多執行緒安全,比餓漢模式好點,它是需要的時候才例項化Singleton物件。
缺點:呼叫getInstance的時候因為加了synchronized鎖,所以其他的執行緒呼叫的時候必須等待,這樣造成了不必要的資源開銷。
DCL模式
Double Check Lock 模式,用的時候初始化,而且不需要getInstance方法進行同步
public class Singleton{
private static volatile Singleton mInstance;//注意volatile這個關鍵字
public static Singleton getInstance() {
if(mInstance == null) {//第一次檢查
synchronized(Singleton.class){//鎖的是Singleton.class檔案確保多執行緒安全
if(mInstance == null) {//第二次檢查
mInstance =new Singleton();
}
}
}
return mInstance;
}
}
volatile 這個關鍵字必須要用的原因
上面程式碼中mInstance =new Singleton(); 其實並不是一個原子操作,編譯後大致做了下面3件事情
1)給Singleton分配記憶體空間
2)建構函式,初始化成員變數
3)mInstance物件指向Singleton分配出來的儲存空間中
問題在於 Java編譯器允許處理器亂序執行,所以上面的可能是1->3->2 比如兩個執行緒A,B分別呼叫了getInstance 靜態函式,A執行了 1->3->2的順序,當執行3的時候,B執行緒call getInstance 靜態函式獲取到的mInstance是非空的,直接返回,這個時候B執行緒直接用這個例項就會有問題,因為此時該例項還沒有初始化.這樣呼叫的話就會報錯.
基於上面的原因 JDK1.5之後引入了volatile這個關鍵字,使編譯器每次都是按1->2->3順序執行,這樣就不會有多執行緒的問題,執行緒也安全。
DCL的優點:資源的利用率高,只有在使用的時候才初始化對應的空間.而且高效的實現執行緒同步.
DCL的缺點:使用了volatile關鍵字,第一次載入的速度上稍微慢了點.
靜態內部類
它是利用了Java虛擬機器載入類的特性來解決了執行緒安全,資源消耗等問題.
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.mInstance;
}
public static class SingletonHolder {
private static final Singleton mInstance = new Singleton()
}
}
這種方式, 通過JVM的類載入方式(虛擬機器會保證一個類的初始化在多執行緒環境中被正確的加鎖、同步), 來保證了多執行緒併發訪問的正確性,由於靜態內部類的載入特性--在使用時候才載入,所以實現了懶載入的模式。
優點:
實現執行緒安全,實現懶載入
缺點:
必須依賴Java虛擬機器
列舉單例
public enum Singleton{
INSTANCE;
}
優點:單元素列舉不僅能避免多執行緒同步問題,防止反序列化時重新建立新的物件
Android 用單例的例子
public final class InputMethodManager {
static InputMethodManager sInstance;
...
public static InputMethodManager getInstance() {
synchronized (InputMethodManager.class) {
if (sInstance == null) {
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
sInstance = new InputMethodManager(service, Looper.getMainLooper());
}
return sInstance;
}
}
....
如InputMethodManager利用了懶載入的模式,但是執行緒不安全.沒有加volatile關鍵字
public static synchronized CalendarDatabaseHelper getInstance(Contextcontext)
{
if (sSingleton == null)
{
sSingleton = newCalendarDatabaseHelper(context);
}
return sSingleton;
}
採用懶漢模式的CalendarDatabaseHelper類,對Calendar資料庫操作
結論:
1)實現單例模式分3步:構造器私有化,宣告私有靜態變數,提供靜態獲取例項的方法.
2)如果是單執行緒推薦懶載入模式,如果是多執行緒推薦靜態內部類的方式實現單例
3)對資料庫操作,對資源訪問,對IO操作等最好提供單例模式來處理
相關文章
- 深入探討單例模式單例模式
- Android設計模式之單例模式Android設計模式單例
- 設計模式 單例模式設計模式單例
- 設計模式——單例模式設計模式單例
- [設計模式] 單例模式設計模式單例
- 設計模式-單例模式設計模式單例
- 設計模式 —— 單例模式設計模式單例
- 設計模式(單例模式)設計模式單例
- 設計模式-單例模式、多例模式設計模式單例
- 設計模式之單例設計模式設計模式單例
- Java設計模式-單例模式Java設計模式單例
- 設計模式之單例模式設計模式單例
- Java設計模式【單例模式】Java設計模式單例
- 常用設計模式-單例模式設計模式單例
- 設計模式之---單例模式設計模式單例
- 設計模式(二)——單例模式設計模式單例
- Java設計模式 | 單例模式Java設計模式單例
- 001設計模式:單例模式設計模式單例
- # Python設計模式 單例模式Python設計模式單例
- 設計模式一(單例模式)設計模式單例
- 設計模式之☞單例模式設計模式單例
- Java設計模式——單例模式Java設計模式單例
- Java設計模式--單例模式Java設計模式單例
- Python設計模式——單例模式Python設計模式單例
- 設計模式—singleton(單例模式)設計模式單例
- python設計模式-單例模式Python設計模式單例
- Java設計模式–單例模式Java設計模式單例
- js設計模式--單例模式JS設計模式單例
- 設計模式(一)_單例模式設計模式單例
- 設計模式總結 —— 單例設計模式設計模式單例
- JavaScript設計模式初探--單例設計模式JavaScript設計模式單例
- 單例設計模式單例設計模式
- Java常用設計模式-單例模式Java設計模式單例
- GoLang設計模式04 - 單例模式Golang設計模式單例
- 極簡設計模式-單例模式設計模式單例
- 01 設計模式之單例模式設計模式單例
- 重學設計模式-單例模式設計模式單例
- js設計模式之單例模式JS設計模式單例
- Javascript 設計模式之單例模式JavaScript設計模式單例