天天看點

《Android源碼設計模式解析與實戰》讀書筆記(二)

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。                    https://blog.csdn.net/qq_17766199/article/details/50225395                

 第二章、單例模式

單例模式應該是日常使用最為廣泛的一種模式了。他的作用是確定某個類隻有一個執行個體,避免産生多個對象消耗過多的資源。比如對資料庫的操作時,就可以使用單例模式。

1.各種單例

(1)餓漢模式

public class Singleton {  

     private static Singleton instance = new Singleton();  

     private Singleton (){

     }

     public static Singleton getInstance() {  

     return instance;  

     }  

 } 

這種寫法是在類裝載時就執行個體化instance,他避免了多線程的同步問題。但是不能保證有别的方式去裝載,沒有達到懶加載。

(2)懶漢模式(線程不安全)

public class Singleton {  

      private static Singleton instance;  

      private Singleton (){

      }   

      public static Singleton getInstance() {  

      if (instance == null) {  

          instance = new Singleton();  

      }  

      return instance;  

      }  

 } 

達到了懶加載,但是在多線程不能正常工作。

(3)懶漢模式(線程安全)

public class Singleton {  

      private static Singleton instance;  

      private Singleton (){

      }

      public static synchronized Singleton getInstance() {  

      if (instance == null) {  

          instance = new Singleton();  

      }  

      return instance;  

      }  

 }  

這種寫法能夠在多線程中很好的工作,但是每次調用getInstance方法都會進行同步,反應稍慢,還會造成不必要的開銷,是以者這種不建議使用。

(4)DCL單例(雙重檢查鎖定)

public class Singleton {  

      private volatile static Singleton singleton;  

      private Singleton (){

      }   

      public static Singleton getSingleton() {  

      if (singleton == null) {  

          synchronized (Singleton.class) {  

          if (singleton == null) {  

              singleton = new Singleton();  

          }  

         }  

     }  

     return singleton;  

     }  

 }  

這種寫法在getSingleton方法中對singleton進行了兩次判空,第一次是為了不必要的同步,第二次是為了在null的情況下建立執行個體。我們會發現上面代碼有一個volatile關鍵字,因為在這裡會有DCL失效問題,原因是Java編譯器允許處理器亂序執行。那麼為了解決這個問題,在JDK1.5之後,具體化了volatile關鍵字,隻要定義時加上他,可以保證執行的順序,雖然會影響性能。這種方式第一次加載時會稍慢,在高并發環境會有缺陷,但是一般能夠滿足需求。

(5)靜态内部類單例模式

public class Singleton {  

      private Singleton (){

      }

      public static final Singleton getInstance() {  

          return SingletonHolder.INSTANCE;  

      } 

      private static class SingletonHolder {  

      private static final Singleton INSTANCE = new Singleton();  

      }   

  }  

這種是推薦使用的單例模式實作方式。當第一次加載Singleton類時并不會初始化INSTANCE,隻有在第一次調用getInstance方法時才會導緻INSTANCE被初始化。這種方式不僅能夠保證線程安全,也能保證單例對象的唯一性,同時也延長了單例的執行個體化。

(6)枚舉單例

public enum Singleton {  

     INSTANCE;  

     public void whateverMethod() {  

     }  

 }  

這種方式是Effective Java作者Josh Bloch 提倡的方式,它不僅能避免多線程同步問題,而且還能防止反序列化重新建立新的對象。

(7)使用容器實作單例模式

public class SingletonManager { 

private static Map<String, Object> objMap = new HashMap<String,Object>();

private Singleton() { }

public static void registerService(String key, Objectinstance) {

if (!objMap.containsKey(key) ) {

objMap.put(key, instance) ;

}

}

public static ObjectgetService(String key) {

return objMap.get(key) ;

}

}

将多種單例類型注入到一個統一的管理類中,在使用時根據key擷取對象對應類型的對象。這種方式使得我們可以管理多種類型的單例,并且在使用時可以通過統一的接口進行擷取操作,降低了使用者的使用成本,也對使用者隐藏了具體實作,降低了耦合度。

2.Android源碼中的單例模式

在Android系統中,我們經常會通過Context擷取系統級别的服務,如WindowsManagerService、ActivityManagerService等,更常用的是一個LayoutInflater的類,這些服務會在合适的時候以單例的形式注冊在系統中,在我們需要的時候就通過Context的getSystemService(String name)擷取。

3.總結

優點:

(1)由于單例模式在記憶體中隻有一個執行個體,減少了記憶體開支,特别是一個對象需要頻繁的建立、銷毀時,而且建立或銷毀時性能又無法優化,單例模式的優勢就非常明顯。 

(2)單例模式可以避免對資源的多重占用,例如一個檔案操作,由于隻有一個執行個體存在記憶體中,避免對同一資源檔案的同時操作。 

(3)單例模式可以在系統設定全局的通路點,優化和共享資源通路,例如,可以設計一個單例類,負責所有資料表的映射處理。

缺點:

(1)單例模式一般沒有接口,擴充很困難,若要擴充,隻能修改代碼來實作。 

(2)單例對象如果持有Context,那麼很容易引發記憶體洩露。此時需要注意傳遞給單例對象的Context最好是Application Context。

--------------------- 

作者:唯鹿 

來源:CSDN 

原文:https://blog.csdn.net/qq_17766199/article/details/50225395 

版權聲明:本文為部落客原創文章,轉載請附上博文連結!