單例模式(Singleton Pattern):用來建立獨一無二的,只能有一個實例的對象的入場券。html
在咱們進行開發的時候,有些對象咱們只須要一個,好比:配置文件,工具類,線程池、緩存、日誌對象等。若是創造出多個實例,就會致使許多問題,好比佔用資源過多,不一致的結果等。使用單例模式就能保證在程序中須要的實例只有一個。編程
單例模式的類型:懶漢模式、餓漢模式。緩存
下面是單例模式的類圖:安全
咱們將建立一個單例對象類 - Singleton。單例對象(Singleton)類的構造函數是私有的,而且具備自身的靜態實例。多線程
Singleton類提供了一個靜態方法來獲取其靜態實例到外部世界。SingletonTest或示例類將使用Singleton類提供的靜態方法來獲取Singleton對象。yii
餓漢式是在建立自身的靜態實例的時候就直接實例化單例對象,而後在提供的靜態方法中直接返回這個實例對象。函數
1 /** 2 * 單例模式(餓漢模式) 3 * @author admin 4 * 5 */ 6 public class Singleton { 7 //1.將構造方法私有化,不容許外部直接建立對象 8 private Singleton(){ 9 } 10 11 //2.建立類的惟一實例,使用private,static修飾 12 private static Singleton instance = new Singleton(); 13 14 //3.提供一個用於獲取實例的方法,使用public static 修飾 15 public static Singleton getInstance(){ 16 return instance; 17 } 18 }
懶漢式在建立自身的靜態實例的時候不直接實例化單例對象,只有在外部調用獲取單例對象的靜態方法的時候纔會判斷單例對象是否已經存在,若是 不存在則建立一個並返回,若是已經存在則直接返回。工具
1 /** 2 * 單例模式(懶漢模式) 3 * @author admin 4 */ 5 public class Singleton2 { 6 //1.將構造方法私有化,不容許外邊直接建立對象 7 private Singleton2(){ 8 } 9 //2.聲明類的惟一實例,使用private,static修飾,可是此處不實例化 10 private static Singleton2 instance; 11 //3.提供一個用於獲取實例的方法,使用public static修飾 12 public static Singleton2 getInstance(){ 13 if (instance == null) { 14 instance = new Singleton2(); 15 } 16 return instance; 17 } 18 }
1 /** 2 * 單例模式的測試類 3 * @author admin 4 * 5 */ 6 public class SingletonTest { 7 public static void main(String[] args) { 8 //餓漢模式 9 Singleton s1 = Singleton.getInstance(); 10 Singleton s2 = Singleton.getInstance(); 11 12 if (s1 == s2) { 13 System.out.println("s1和s2是同一個對象"); 14 }else { 15 System.out.println("s1和s2不是同一個對象"); 16 } 17 18 //懶漢模式 19 Singleton2 s3 = Singleton2.getInstance(); 20 Singleton2 s4 = Singleton2.getInstance(); 21 if (s3 == s4) { 22 System.out.println("s3和s4是同一個對象"); 23 }else { 24 System.out.println("s3和s4不是同一個對象"); 25 } 26 } 27 }
測試結果:性能
從測試結果能夠看出來,獲取的對象是同一個對象,也就是說,返回的是單例對象。測試
上面的代碼在普通的應用程序中沒有任何任何問題,可是在多線程中使用的時候就會發現,返回的單例對象並非惟一的,並且多個不一樣的單例對象,這就說明在多線程中,單例模式產生的單例對象並非"惟一"的。要解決這個問題,有3種辦法(其中兩種方法都是針對懶漢式的),這3種方法在解決多線程問題的同時也有本身的缺點:
1 /** 2 * 單例模式(懶漢模式) 3 * @author admin 4 */ 5 public class Singleton2 { 6 //1.將構造方法私有化,不容許外邊直接建立對象 7 private Singleton2(){ 8 9 } 10 //2.聲明類的惟一實例,使用private,static修飾,可是此處不實例化 11 private volatile static Singleton2 instance; 12 //3.提供一個用於獲取實例的方法,使用public static修飾 13 public static Singleton2 getInstance(){//檢查實例,若是不存在就進入同步區塊 14 if (instance == null) { 15 synchronized (Singleton2.class){//注意,只有第一次才完全執行這裏的代碼 16 if (instance == null) {//進入區塊後,再檢查一次,若是仍是null,才建立實例 17 instance = new Singleton2(); 18 } 19 } 20 } 21 return instance; 22 } 23 }
volatile關鍵字確保:當單例變量被初始化成Singleton實例時,多個線程正確地處理單例變量。若是性能問題是關注的重點,那麼這個方法能夠大大地減小getInstance()的時間消耗。可是該方法也有其缺點,那就是雙重檢查加鎖不適用於1.4及更早版本的Java。在1.4及其更早的版本中,許多JVM對於volatile關鍵字的實現會致使雙重檢查加鎖的實效。若是不能使用Java5以上的版本,而必須使用舊版本,那麼該方法就沒法解決多線程的問題。
好了單例模式的敘述到此就結束了,若是有什麼講解的不正確的地方,歡迎你們多多指教!
文章部份內容引用自以下地址:http://www.yiibai.com/design_pattern/singleton_pattern.html