中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解析Android Java語言中單例這種設計模式

發布時間:2021-11-26 17:19:21 來源:億速云 閱讀:154 作者:柒染 欄目:移動開發

本篇文章為大家展示了如何解析Android Java語言中單例這種設計模式,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

概念

單例模式,又稱單件模式或者單子模式,指的是一個類只有一個實例,并且提供一個全局訪問點。

實現思路

  • 在單例的類中設置一個private靜態變量sInstance,sInstance類型為當前類,用來持有單例***的實例。

  • 將(無參數)構造器設置為private,避免外部使用new構造多個實例。

  • 提供一個public的靜態方法,如getInstance,用來返回該類的***實例sInstance。

其中上面的單例的實例可以有以下幾種創建形式,每一種實現都需要保證實例的***性。

餓漢式

餓漢式指的是單例的實例在類裝載時進行創建。如果單例類的構造方法中沒有包含過多的操作處理,餓漢式其實是可以接受的。

餓漢式的常見代碼如下,當SingleInstance類加載時會執行

private static SingleInstance sInstance = new SingleInstance();

初始化了***的實例,然后getInstance()直接返回sInstance即可。

public class SingleInstance {   private static SingleInstance sInstance = new SingleInstance();      private SingleInstance() {   }      public static SingleInstance getInstance() {       return sInstance;   } }

餓漢式的問題

  • 如果構造方法中存在過多的處理,會導致加載這個類時比較慢,可能引起性能問題。

  • 如果使用餓漢式的話,只進行了類的裝載,并沒有實質的調用,會造成資源的浪費。

懶漢式

懶漢式指的是單例實例在***次使用時進行創建。這種情況下避免了上面餓漢式可能遇到的問題。

但是考慮到多線程的并發操作,我們不能簡簡單單得像下面代碼實現。

public class SingleInstance {   private static SingleInstance sInstance;   private SingleInstance() {   }      public static SingleInstance getInstance() {       if (null == sInstance) {           sInstance = new SingleInstance();       }       return sInstance;   } }

上述的代碼在多個線程密集調用getInstance時,存在創建多個實例的可能。比如線程A進入null == sInstance這段代碼塊,而在A線程未創建完成實例時,如果線程B也進入了該代碼塊,必然會造成兩個實例的產生。

synchronized修飾方法

使用synchrnozed修飾getInstance方法可能是最簡單的一個保證多線程保證單例***性的方法。
synchronized修飾的方法后,當某個線程進入調用這個方法,該線程只有當其他線程離開當前方法后才會進入該方法。所以可以保證getInstance在任何時候只有一個線程進入。

public class SingleInstance {   private static SingleInstance sInstance;   private SingleInstance() {   }      public static synchronized SingleInstance getInstance() {       if (null == sInstance) {           sInstance = new SingleInstance();       }       return sInstance;   } }

但是使用synchronized修飾getInstance方法后必然會導致性能下降,而且getInstance是一個被頻繁調用的方法。雖然這種方法能解決問題,但是不推薦。

雙重檢查加鎖

使用雙重檢查加鎖,首先進入該方法時進行null == sInstance檢查,如果***次檢查通過,即沒有實例創建,則進入synchronized控制的同步塊,并再次檢查實例是否創建,如果仍未創建,則創建該實例。

雙重檢查加鎖保證了多線程下只創建一個實例,并且加鎖代碼塊只在實例創建的之前進行同步。如果實例已經創建后,進入該方法,則不會執行到同步塊的代碼。

public class SingleInstance {   private static volatile SingleInstance sInstance;   private SingleInstance() {   }      public static SingleInstance getInstance() {       if (null == sInstance) {           synchronized (SingleInstance.class) {               if (null == sInstance) {                   sInstance = new SingleInstance();               }           }       }       return sInstance;   } }

volatile是什么

Volatile是輕量級的synchronized,它在多處理器開發中保證了共享變量的“可見性”。可見性的意思是當一個線程修改一個共享變量 時,另外一個線程能讀到這個修改的值。使用volatile修飾sInstance變量之后,可以確保多個線程之間正確處理sInstance變量。
關于volatile,可以訪問深入分析Volatile的實現原理了解更多。

利用static機制

在Java中,類的靜態初始化會在類被加載時觸發,我們利用這個原理,可以實現利用這一特性,結合內部類,可以實現如下的代碼,進行懶漢式創建實例。

public class SingleInstance {   private SingleInstance() {   }      public static SingleInstance getInstance() {       return SingleInstanceHolder.sInstance;   }      private static class SingleInstanceHolder {       private static SingleInstance sInstance = new SingleInstance();   } }

關于這種機制,可以具體了解雙重檢查鎖定與延遲初始化

好奇問題

真的只有一個對象么

其實,單例模式并不能保證實例的***性,只要我們想辦法的話,還是可以打破這種***性的。以下幾種方法都能實現。

  • 使用反射,雖然構造器為非公開,但是在反射面前就不起作用了。

  • 如果單例的類實現了cloneable,那么還是可以拷貝出多個實例的。

  • Java中的對象序列化也有可能導致創建多個實例。避免使用readObject方法。

  • 使用多個類加載器加載單例類,也會導致創建多個實例并存的問題。

單例可以繼承么

單例類能否被繼承需要分情況而定。

可以繼承的情況

當子類是父類單例類的內部類時,繼承是可以的。

public class BaseSingleton {   private static volatile BaseSingleton sInstance;      private BaseSingleton() {          }      public static BaseSingleton getInstance() {       if (null == sInstance) {           synchronized(BaseSingleton.class) {               if (null == sInstance) {                   sInstance = new BaseSingleton();               }           }       }       return sInstance;   }      public static class  MySingleton extends BaseSingleton {          }    }

但是上面僅僅是編譯和執行上允許的,但是繼承單例沒有實際的意義,反而會變得更加事倍功半,其代價要大于新寫一個單例類。感興趣的童鞋可以嘗試折騰一下。

不可以繼承的情況

如果子類為單獨的類,非單例類的內部類的話,那么在編譯時就會出錯Implicit super constructor BaseSingleton() is not visible for default constructor. Must define an explicit constructor,主要原因是單例類的構造器是private,解決方法是講構造器設置為可見,但是這樣做就無法保證單例的***性。所以這種方式不可以繼承。

總的來說,單例類不要繼承。

 

單例 vs static變量

全局靜態變量也可以實現單例的效果,但是使用全局變量無法保證只創建一個實例,而且使用全局變量的形式,需要團隊的約束,執行起來可能會出現問題。

關于GC

因為單例類中又一個靜態的變量持有單例的實例,所以相比普通的對象,單例的對象更不容易被GC回收掉。單例對象的回收應該發生在其類加載器被GC回收掉之后,一般不容易出現。

上述內容就是如何解析Android Java語言中單例這種設計模式,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

会理县| 荔浦县| 马龙县| 高邑县| 木兰县| 黄山市| 合肥市| 酉阳| 丰都县| 湖南省| 宿迁市| 邯郸县| 榆中县| 彭州市| 陈巴尔虎旗| 弋阳县| 阿拉尔市| 自贡市| 宁夏| 甘肃省| 临安市| 昭觉县| 博客| 瓦房店市| 马鞍山市| 道孚县| 洛扎县| 秦皇岛市| 南丰县| 桓台县| 朔州市| 望都县| 昆明市| 潜江市| 海伦市| 阜宁县| 阳原县| 嘉禾县| 寿宁县| 陇西县| 龙口市|