Java單例模式


什么是單例模式

  單例模式是在程序中,一個類保證只有一個實例,並提供統一的訪問入口。

為什么要用單例模式

  • 節省內存 節省計算
    • 如對象實例中的一樣的,那就不用每次都創建一個對象
  • 方便管理
    • 因為單例提供一個統一的訪問入口,不需要創建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 }

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM