什么是單例模式
單例模式是在程序中,一個類保證只有一個實例,並提供統一的訪問入口。
為什么要用單例模式
- 節省內存 節省計算
- 如對象實例中的一樣的,那就不用每次都創建一個對象
- 方便管理
- 因為單例提供一個統一的訪問入口,不需要創建N多個對象,很多工具類都用了單例實現,如日志、字符串工具類
- 保證結果正確
- 比如統計網站的訪問次數等等
單例的實現方式
- 餓漢式
- 程序啟動的時候就會實例化
1 public class Singleton { 2 3 private static Singleton singleton = new Singleton(); 4 5 private Singleton(){} 6 7 public static Singleton getInstance(){ 8 return singleton; 9 } 10 }
餓漢靜態代碼塊形勢
1 public class Singleton { 2 3 private static Singleton singleton; 4 static { 5 singleton = new Singleton(); 6 } 7 private Singleton(){} 8 9 public static Singleton getInstance(){ 10 return singleton; 11 } 12 }
- 懶漢式
- 非線程安全的實現
1 public class Singleton { 2 3 private static Singleton singleton; 4 private Singleton(){} 5 6 public static Singleton getInstance(){ 7 if (singleton == null){ 8 return singleton = new Singleton(); 9 } 10 return singleton; 11 } 12 }
-
- 線程安全的實現,單性能低
1 public class Singleton { 2 3 private static Singleton singleton; 4 private Singleton(){} 5 6 public static synchronized Singleton getInstance(){ 7 if (singleton == null){ 8 return singleton = new Singleton(); 9 } 10 return singleton; 11 } 12 }
-
- 線程安全的實現,雙重校驗
- 注意:兩個校驗都必須加,如果第二個沒有加校驗,當兩個線程都通過了第一個if校驗,此時會有一個線程進入同步代碼塊,創建singleton實例,接着第二個線程也會進入同步代碼塊,並會在創建一個singleton。那么這樣就破壞了單例。如果不加第一個if校驗,那么所有的程序就會串行執行,影響執行效率。所以兩個校驗都必須存在
- 線程安全的實現,雙重校驗
1 public class Singleton { 2 /**由於 return singleton = new Singleton(); 這行代碼在JVM中會分為三步處理 3 * 1.給singleton分配內存空間 4 * 2.調用singleton的構造函數開初始化 5 * 3.將singleton對象指向分配的內存空間(這步執行了就singleton就不是null了) 6 * 7 * 由於CPU會對這三個步驟重排序,如果順序是1 3 2,那么就可能出現singleton就不是空的,但並沒有初始化singleton 8 * 這樣第二個線程可能拿到的就是為初始化的singleton,所以使用volatile來修飾singleton,防止重排序的問題 9 */ 10 private static volatile Singleton singleton; 11 private Singleton(){} 12 13 public static Singleton getInstance(){ 14 if (singleton == null){ 15 synchronized (Singleton.class) { 16 if (singleton == null) { 17 return singleton = new Singleton(); 18 } 19 } 20 } 21 return singleton; 22 } 23 }
-
- 懶漢之靜態內部類的方式
- 這種方式能保證線程的安全線性,當Singleton被裝載時,並不會立刻實例化靜態內部類SingletonInstance,而是在需要時才會實例化
- 懶漢之靜態內部類的方式
1 public class Singleton { 2 3 private static class SingletonInstance{ 4 private static final Singleton singleton = new Singleton(); 5 } 6 private Singleton(){} 7 8 public static Singleton getInstance(){ 9 return SingletonInstance.singleton; 10 } 11 }
- 枚舉實現單例
- 實現簡單、線程安全、可以防止反序列化、反射的方式破壞單例模式,如果通過反序列化或反射的方式創建實例,會拋出異常。這種方式是最好的實現的方式
1 public enum Singleton{ 2 INSTANCE; 3 public void whateverMethod(){ 4 } 5 }
