Java-單例模式詳解(圖文並茂,簡單易懂)


PS:首先我們要先知道什么是單例,為什么要用單例,用的好處是什么等問題來看。

1:java中單例模式是一種常見的設計模式,單例模式的寫法有好幾種,這里主要介紹兩種:懶漢式單例、餓漢式單例

單例模式有以下特點:  

  1、單例類只能有一個實例。
  2、單例類必須自己創建自己的唯一實例。
  3、單例類必須給所有其他對象提供這一實例。

目的

  單例模式確保某個類只有一個實例,而且自行實例化並向整個系統提供這個實例。在計算機系統中,線程池、緩存、日志對象、對話框、打印機、顯卡的驅動程序對象常被設計成單例。這些應用都或多或少具有資源管理器的功能。每台計算機可以有若干個打印機,但只能有一個Printer Spooler,以避免兩個打印作業同時輸出到打印機中。每台計算機可以有若干通信端口,系統應當集中管理這些通信端口,以避免一個通信端口同時被兩個請求同時調用。總之,選擇單例模式就是為了避免不一致狀態,避免政出多頭。

2:懶漢式

先把單例類寫出來

public class SingletonTest {
    //懶漢式單例類.在第一次調用的時候實例化自己 
    private SingletonTest() {}
        private static SingletonTest single=null;
        //靜態工廠方法 
        public static SingletonTest getInstance() {
             if (single == null) {  
                 single = new SingletonTest();
                 System.out.println("創建一次");
             }  
            return single;
        }
        
        public void show(){
            System.out.println("我是show");
        }

}

這里直接上代碼,代碼中有詳解

public class SingletonTest2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //故意寫獲取兩次,創建兩個對象
        SingletonTest singleton=SingletonTest.getInstance();
        SingletonTest singleton2=SingletonTest.getInstance();
        
        //Singleton對象只創建一次,但是寫兩次還是可以的,而且方法都是可以調用的,但是看下面
        singleton.show();
        singleton2.show();
        
        //兩個對象的表現形式一樣
        if(singleton == singleton2){
            System.out.println("該對象的字符串表示形式:");
            System.out.println("singleton :"+singleton.toString());
            System.out.println("singleton2:"+singleton2.toString());
        }
}

 


 

由上面的圖可以看出就算多創建幾個對象,在底部也是只有一個singleton對象實例,而且創建出來的對象的字符串表現形式也是一樣的,有的人肯定有疑問,那平常兩個對象是什么樣子的呢,我下面給你解釋說明,在這之前我寫說一下這個懶漢式需要注意的地方,它是線程不安全的,並發環境下很可能出現多個Singleton實例,有很多方法可以解決,比如說同步鎖,靜態內部類等,這里主要說靜態內部類,這個比較好點,

 

public class Singleton3 {  
    private static class SingletonHolder {  
       private static final Singleton3 INSTANCE = new Singleton3();  
    }  
    private Singleton3 (){}  
    public static final Singleton3 getInstance() {  
        System.out.println("singleton創建");
       return SingletonHolder.INSTANCE;  
    }  
}

 

調用:

 

Singleton3 singleton3=Singleton3.getInstance();
        Singleton3 singleton4=Singleton3.getInstance();
        if(singleton3 == singleton4){
            System.out.println("該對象的字符串表示形式:");
            System.out.println("singleton3:"+singleton3.toString());
            System.out.println("singleton4:"+singleton4.toString());
        }

 


結果圖:

 

這里我也是創建了兩個對象來說明,神奇的是打印了兩次singleton創建,這難道是又創建成功了的對象嗎?答案是:雖然打印了兩次,對象名也有兩個,但是該對象的字符串表示形式還是一樣的,而且大家都知道static的用法,就是在類被加載的同時該singleton對象就已經被創建,后期不會再被創建,就算后期自己又調用了getInstance()方法,但底層還是公用的一個Singleton對象.

同樣,我寫了一個普通的類,來同時創建兩個對象,並且打印他們的toString()方法,如下:

 

     QuBie qb1=new QuBie();
        QuBie qb2=new QuBie();
        if(qb1 == qb2){
            System.out.println("該對象的字符串表示形式:");
            System.out.println("singleton3:"+qb1.toString());
            System.out.println("singleton4:"+qb2.toString());
        }else{
            System.out.println("該對象的字符串表示形式:");
            System.out.println("singleton3:"+qb1.toString());
            System.out.println("singleton4:"+qb2.toString());
        }

 



 

由此可看出來對象的字符串表示形式是不一樣的

3:餓漢式單例

餓漢式單例類.在類初始化時,已經自行實例化

public class Singleton1 {
  private Singleton1() {}
  private static final Singleton1 single = new Singleton1();
  //靜態工廠方法 
  public static Singleton1 getInstance() {
      return single;
  }
}


因為這本身就是static修飾的方法,所以是在類加載的時候被創建,后期不會再改變,所以線程是安全的。

4:雙檢鎖/雙重校驗鎖

描述:采用雙鎖機制,安全且在多線程情況下能保持高性能。多線程安全

 

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

這里的兩次判斷,第一判斷:效率,第二判斷:避免同步。之所以這樣是因為避免加鎖后,再次加鎖。大大增強了執行效率。

 

(適配器、單例、靜態代理、簡單工廠設計模式)https://www.cnblogs.com/cmusketeer/p/8146510.html




免責聲明!

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



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