Singleton:在Java中即指單例設計模式,它是軟件開發中最常用的設計模式之一。
單:指唯一
例:指實例
單例設計模式,即某個類在整個系統中只能有一個實例對象可被獲取和使用的代碼模式。
要點:
一、單例類只能有一個實例
- 保證構造器私有化(防止通過構造器實例化)
二、單例類必須自信創建這個實例
- 在單例類中創建一個靜態變量來保存這個唯一的實例
三、單例類必須自行向整個系統提供這個實例
- 對外提供該實例對象的獲取方式
- 直接暴露該實例對象
- 用靜態變量的get方法獲取該實例對象
單例的幾種常見形式
餓漢式:直接創建對象,不存在線程安全問題
- 直接實例化餓漢式(簡介直觀)
1 /** 2 * 單例餓漢式一(1) 3 * 直接實例化餓漢式(簡潔直觀) 4 * 對外提供獲取該實例對象的方式: 5 * (1)直接暴露 6 * (2)用靜態變量的get方法獲取 7 */ 8 public class SingletonHungry1 { 9 10 public static final SingletonHungry1 INSTANCE = new SingletonHungry1(); 11 12 private SingletonHungry1() {} 13 } 14 15 16 /** 17 * 單例餓漢式一(2) 18 * 直接實例化餓漢式(簡潔直觀) 19 * 對外提供獲取該實例對象的方式: 20 * (1)直接暴露 21 * (2)用靜態變量的get方法獲取 22 */ 23 public class SingletonHungry2 { 24 25 private static final SingletonHungry2 INSTANCE = new SingletonHungry2(); 26 27 private SingletonHungry2() {} 28 29 public static SingletonHungry2 getInstance() { 30 return INSTANCE; 31 } 32 }
- 枚舉式(最簡潔)
1 /** 2 * 單例餓漢式二 3 * 枚舉式(最簡潔) 4 */ 5 public enum SingletonHungry3 { 6 INSTANCE 7 }
- 靜態代碼塊餓漢式(適合復雜實例化)
1 /** 2 * 單例餓漢式三 3 * 靜態代碼塊餓漢式(適合復雜實例化) 4 */ 5 public class SingletonHungry4 { 6 7 public static final SingletonHungry4 INSTANCE; 8 9 private String info; 10 11 static { 12 // 這里用來實現復雜的實例化 13 // ......復雜代碼 14 try { 15 Properties pro = new Properties(); 16 pro.load(SingletonHungry4.class.getClassLoader().getResourceAsStream("singleton.properties")); 17 INSTANCE = new SingletonHungry4(pro.getProperty("info")); 18 } catch (IOException e) { 19 throw new RuntimeException(e); 20 } 21 } 22 23 private SingletonHungry4(String info) { 24 this.info = info; 25 } 26 }
懶漢式:延遲創建對象
- 線程不安全(適用於單線程)
1 /** 2 * 單例懶漢式一 3 * 線程不安全(適用於單線程) 4 */ 5 public class SingletonLazy1 { 6 7 private static SingletonLazy1 INSTANCE; 8 9 private SingletonLazy1() {} 10 11 public static SingletonLazy1 getInstance() { 12 if (INSTANCE == null) { 13 try { 14 Thread.sleep(100); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 INSTANCE = new SingletonLazy1(); 19 } 20 return INSTANCE; 21 } 22 }
- 線程安全(適用於多線程)
1 /** 2 * 單例懶漢式二(1) 3 * 線程安全(適用於多線程) 4 */ 5 public class SingletonLazy2 { 6 7 private static SingletonLazy2 INSTANCE; 8 9 private SingletonLazy2() {} 10 11 public static SingletonLazy2 getInstance() { 12 synchronized (SingletonLazy2.class) { 13 if (INSTANCE == null) { 14 try { 15 Thread.sleep(100); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 INSTANCE = new SingletonLazy2(); 20 } 21 } 22 return INSTANCE; 23 } 24 } 25 26 /** 27 * 單例懶漢式二(2) 28 * 線程安全(適用於多線程,優化效率) 29 */ 30 public class SingletonLazy3 { 31 32 private static SingletonLazy3 INSTANCE; 33 34 private SingletonLazy3() {} 35 36 public static SingletonLazy3 getInstance() { 37 if (INSTANCE == null) { // 不等於空直接返回,提高效率 38 synchronized (SingletonLazy3.class) { 39 if (INSTANCE == null) { 40 try { 41 Thread.sleep(100); 42 } catch (InterruptedException e) { 43 e.printStackTrace(); 44 } 45 INSTANCE = new SingletonLazy3(); 46 } 47 } 48 } 49 50 return INSTANCE; 51 } 52 }
- 靜態內部類形式(適用於多線程)
在內部類被加載和初始化時,才創建INSTANCE實例對象
靜態內部類不會自動隨着外部類的加載和初始化而初始化,它是要單獨去加載和初始化的
因為是在內部類加載和初始化時創建的,因此是線程安全的
1 /** 2 * 單例懶漢式三 3 * 靜態內部類(適用於多線程) 4 * 在內部類被加載和初始化時,才創建INSTANCE實例對象 5 * 靜態內部類不會自動隨着外部類的加載和初始化而初始化,它是要單獨去加載和初始化的 6 * 因為是在內部類加載和初始化時,創建的,因此是線程安全的 7 */ 8 public class SingletonLazy4 { 9 10 private SingletonLazy4() {} 11 12 private static class Inner { 13 private static final SingletonLazy4 INSTANCE = new SingletonLazy4(); 14 } 15 16 public static SingletonLazy4 getInstance() { 17 return Inner.INSTANCE; 18 } 19 }
本文用於記錄Singleton的學習,方便以后回顧!學完的東西容易忘,以文章的形式記錄下來。歡迎大家學習和指出文章中的錯誤,謝謝!