標籤:blog 取值 check 高並發 java 並且 類載入 優缺點 enum
No1:
懶漢單例模式優缺點分析
public class Singleton{ private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; }}
優點:單例只有在使用時才會被執行個體化,在一定程度上節約了資源
缺點:第一次載入時需要及時進行執行個體化,反應稍慢,最大的問題是每次調用getInstance都進行同步,造成不必要的同步開銷。
所以這種模式一般不建議使用
No2:
Double Check Lock(DCL)雙重檢查鎖定方式
public class Singleton{ private static Singleton sInstance = null; private Singleton(){} public void doSomething(){ System.out.println("do sth."); } public static Singleton getInstance(){ if(mInstance == null){ synchronized(Singleton.class){ if(mInstance == null){ sInstance = new Singleton(); } } } return sInstance; }}
優點:,第一次執行getInstance時單例對象才會被執行個體化,資源使用率高。第一層對instance判空主要是為了避免不必要的同步,第二層判斷則是為了在null的情況下建立執行個體
缺點:第一次載入時反應稍慢,也由於java記憶體模型的原因偶爾會失敗。再高並發環境下也有一定缺陷,雖然發生機率很小
No3:
靜態內部類單例模式
public class Singleton{ private Singleton(){} public static Singleton getInstance(){ return SingletonHolder.sInstance; } /** *靜態內部類 */ private static class SingletonHolder{ private static final Singleton sInstance = new Singleton(); }}
第一次調用getInstance方法會導致虛擬機器載入SingletonHolder類,這種方式不僅能夠確保安全執行緒,也能夠保證單例對象的唯一性,同時也延遲了單例的執行個體化,所以推薦使用
No4:
枚舉單例
public enum SingletonEnum{ INSTANCE; public void doSomething(){ System.out.println("do sth."); }}
優點:安全執行緒,即使還原序列化也不會重建新的執行個體
No5:
如果想杜絕單例模式對象在被還原序列化時重建對象,那麼必須加入readResolve函數
public final class Singleton implements Serializable{ private static final long serialVersionUID = 0L; private static final Singleton INSTANCE = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return INSTANCE; } private Object readResolve() throws ObjectStreamException{ return INSTANCE; }}
也就是在readResolve方法中將單例對象返回,而不是重建一個新的對象。而對於枚舉,並不存在這個問題
No6:
1)可序列化類別中的欄位類型不是Java的內建類型,那麼該欄位類型也需要實現Serializable介面
2)如果調整了可序列化類別的內部結構,例如新增、去除某個欄位,但沒有修改serialVersionUID,會引發異常。最好的方案是將值設定為0L,只是那些新修改的欄位會為0或者null。
No7:
使用容器實現單例模式
public class SingletonManager{ private static Map<String,Object> objMap = new HashMap<String,Object>(); private SingletonManager(){} public static void registerService(String key,Object instance){ if(!objMap.containsKey(key)){ objMap.put(key,instance); } } public static Object getService(String key){ return objMap.get(key); }}
優點:可以管理多種類型的單例,並且在使用時可以通過統一的介面進行擷取操作,降低了使用者的使用成本,也對使用者隱藏了具體實現,降低了耦合度。
No8:
LayoutInflater.from(Context)來擷取LayoutInflater服務
Context是抽象類別,在Application、Activity、Service中都會存在一個Context對象,即Context的總個數為Activity個數+Service個數+1。
一個Activity的入口是ActivityThread的main函數。
建立Context對象的實作類別是ContextImpl
No9:
從ContextImpl類的部分代碼中可以看到,在虛擬機器第一次載入該類時會註冊各種ServiceFetcher,其中就包含了LayoutInflater Service。將這些服務以索引值對的形式儲存在一個HashMap中,使用者使用時只需要根據key來擷取到對應的ServiceFetcher,然後通過ServiceFetcher對象的getService函數來擷取具體的服務物件。當第一次擷取時,會調用ServiceFetcher的createService函數建立服務物件,然後將該對象緩衝到一個列表中,下次再取值時直接從緩衝中擷取,避免重複建立對象,從而達到單例的效果。系統核心服務以單例形式存在,減少了資源消耗。
No10:
LayoutInflater是一個抽象類別,PolicyManager實際上是一個代理類,實現了IPolicy介面
真正LayoutInflater的實作類別是PhoneLayoutInflater
No11:
Activity的setContentView方法實際上調用的是Window的setContentView,Window是一個抽象類別,具體實作類別是PhoneWindow
No12:
createView相對比較簡單,如果有首碼,那麼構造View的完整路徑,並且將該類載入到虛擬機器中,然後擷取該類的建構函式並且緩衝起來,再通過建構函式來建立該View的對象,最後將View對象返回,這就是解析單個View的過程。通過rInflate的解析之後,整棵視圖樹就構建完畢。
No13:
單例模式的缺點:
1)單例模式一般沒有介面,擴充很困難,若要擴充,除了修改代碼基本上沒有第二種途徑可以實現
2)單例對象如果持有Context,那麼很容易引發記憶體泄露,此時需要注意傳遞給單例對象的Context最好是Application Context
《Android源碼設計模式》--單例模式