自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

談?wù)凙ndroid Java語言中單例這種設(shè)計模式

移動開發(fā) Android
隨著我們編寫代碼的深入,我們或多或少都會接觸到設(shè)計模式,其中單例(Singleton)模式應(yīng)該是我們耳熟能詳?shù)囊环N模式。本文將比較特別的介紹一下Java設(shè)計模式中的單例模式。

[[126280]]

隨著我們編寫代碼的深入,我們或多或少都會接觸到設(shè)計模式,其中單例(Singleton)模式應(yīng)該是我們耳熟能詳?shù)囊环N模式。本文將比較特別的介紹一下Java設(shè)計模式中的單例模式。

概念

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

實現(xiàn)思路

  • 在單例的類中設(shè)置一個private靜態(tài)變量sInstance,sInstance類型為當前類,用來持有單例***的實例。
  • 將(無參數(shù))構(gòu)造器設(shè)置為private,避免外部使用new構(gòu)造多個實例。
  • 提供一個public的靜態(tài)方法,如getInstance,用來返回該類的***實例sInstance。

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

餓漢式

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

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

  1. private static SingleInstance sInstance = new SingleInstance(); 

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

  1. public class SingleInstance { 
  2.   private static SingleInstance sInstance = new SingleInstance(); 
  3.    
  4.   private SingleInstance() { 
  5.   } 
  6.    
  7.   public static SingleInstance getInstance() { 
  8.       return sInstance; 
  9.   } 

餓漢式的問題

  • 如果構(gòu)造方法中存在過多的處理,會導(dǎo)致加載這個類時比較慢,可能引起性能問題。
  • 如果使用餓漢式的話,只進行了類的裝載,并沒有實質(zhì)的調(diào)用,會造成資源的浪費。

懶漢式

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

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

  1. public class SingleInstance { 
  2.   private static SingleInstance sInstance; 
  3.   private SingleInstance() { 
  4.   } 
  5.    
  6.   public static SingleInstance getInstance() { 
  7.       if (null == sInstance) { 
  8.           sInstance = new SingleInstance(); 
  9.       } 
  10.       return sInstance; 
  11.   } 

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

synchronized修飾方法

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

  1. public class SingleInstance { 
  2.   private static SingleInstance sInstance; 
  3.   private SingleInstance() { 
  4.   } 
  5.    
  6.   public static synchronized SingleInstance getInstance() { 
  7.       if (null == sInstance) { 
  8.           sInstance = new SingleInstance(); 
  9.       } 
  10.       return sInstance; 
  11.   } 

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

雙重檢查加鎖

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

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

  1. public class SingleInstance { 
  2.   private static volatile SingleInstance sInstance; 
  3.   private SingleInstance() { 
  4.   } 
  5.    
  6.   public static SingleInstance getInstance() { 
  7.       if (null == sInstance) { 
  8.           synchronized (SingleInstance.class) { 
  9.               if (null == sInstance) { 
  10.                   sInstance = new SingleInstance(); 
  11.               } 
  12.           } 
  13.       } 
  14.       return sInstance; 
  15.   } 

volatile是什么

Volatile是輕量級的synchronized,它在多處理器開發(fā)中保證了共享變量的“可見性”??梢娦缘囊馑际钱斠粋€線程修改一個共享變量 時,另外一個線程能讀到這個修改的值。使用volatile修飾sInstance變量之后,可以確保多個線程之間正確處理sInstance變量。
關(guān)于volatile,可以訪問深入分析Volatile的實現(xiàn)原理了解更多。

利用static機制

在Java中,類的靜態(tài)初始化會在類被加載時觸發(fā),我們利用這個原理,可以實現(xiàn)利用這一特性,結(jié)合內(nèi)部類,可以實現(xiàn)如下的代碼,進行懶漢式創(chuàng)建實例。

  1. public class SingleInstance { 
  2.   private SingleInstance() { 
  3.   } 
  4.    
  5.   public static SingleInstance getInstance() { 
  6.       return SingleInstanceHolder.sInstance; 
  7.   } 
  8.    
  9.   private static class SingleInstanceHolder { 
  10.       private static SingleInstance sInstance = new SingleInstance(); 
  11.   } 

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

好奇問題

真的只有一個對象么

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

  • 使用反射,雖然構(gòu)造器為非公開,但是在反射面前就不起作用了。
  • 如果單例的類實現(xiàn)了cloneable,那么還是可以拷貝出多個實例的。
  • Java中的對象序列化也有可能導(dǎo)致創(chuàng)建多個實例。避免使用readObject方法。
  • 使用多個類加載器加載單例類,也會導(dǎo)致創(chuàng)建多個實例并存的問題。

單例可以繼承么

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

可以繼承的情況

當子類是父類單例類的內(nèi)部類時,繼承是可以的。

  1. public class BaseSingleton { 
  2.   private static volatile BaseSingleton sInstance; 
  3.    
  4.   private BaseSingleton() { 
  5.        
  6.   } 
  7.    
  8.   public static BaseSingleton getInstance() { 
  9.       if (null == sInstance) { 
  10.           synchronized(BaseSingleton.class) { 
  11.               if (null == sInstance) { 
  12.                   sInstance = new BaseSingleton(); 
  13.               } 
  14.           } 
  15.       } 
  16.       return sInstance; 
  17.   } 
  18.    
  19.   public static class  MySingleton extends BaseSingleton { 
  20.        
  21.   } 
  22.    

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

不可以繼承的情況

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

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

單例 vs static變量

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

關(guān)于GC

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

責任編輯:閆佳明 來源: droidyue
相關(guān)推薦

2013-11-26 16:20:26

Android設(shè)計模式

2016-03-28 10:23:11

Android設(shè)計單例

2021-02-01 10:01:58

設(shè)計模式 Java單例模式

2021-03-02 08:50:31

設(shè)計單例模式

2022-06-07 08:55:04

Golang單例模式語言

2022-02-06 22:30:36

前端設(shè)計模式

2024-02-04 12:04:17

2015-09-06 11:07:52

C++設(shè)計模式單例模式

2011-03-16 10:13:31

java單例模式

2021-08-11 17:22:11

設(shè)計模式單例

2022-03-29 07:52:07

設(shè)計模式單例設(shè)計模式java

2023-07-31 12:27:30

單例設(shè)計模式

2022-09-29 08:39:37

架構(gòu)

2023-03-21 15:21:52

開發(fā)程序設(shè)計static

2021-09-07 10:44:35

異步單例模式

2020-09-16 12:18:28

GoJava模式

2021-02-07 23:58:10

單例模式對象

2023-08-03 08:01:27

單例模式結(jié)構(gòu)開發(fā)

2024-03-06 13:19:19

工廠模式Python函數(shù)

2016-10-09 09:37:49

javascript單例模式
點贊
收藏

51CTO技術(shù)棧公眾號