PS:首先咱們要先知道什麼是單例,爲何要用單例,用的好處是什麼等問題來看。html
一、單例類只能有一個實例。
二、單例類必須本身建立本身的惟一實例。
三、單例類必須給全部其餘對象提供這一實例。java
單例模式確保某個類只有一個實例,並且自行實例化並向整個系統提供這個實例。在計算機系統中,線程池、緩存、日誌對象、對話框、打印機、顯卡的驅動程序對象常被設計成單例。這些應用都或多或少具備資源管理器的功能。每臺計算機能夠有若干個打印機,但只能有一個Printer Spooler,以免兩個打印做業同時輸出到打印機中。每臺計算機能夠有若干通訊端口,系統應當集中管理這些通訊端口,以免一個通訊端口同時被兩個請求同時調用。總之,選擇單例模式就是爲了不不一致狀態,避免政出多頭。
設計模式
先把單例類寫出來緩存
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; } }
調用:post
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()); }
結果圖:url
這裏我也是建立了兩個對象來講明,神奇的是打印了兩次singleton建立,這難道是又建立成功了的對象嗎?答案是:雖然打印了兩次,對象名也有兩個,可是該對象的字符串表示形式仍是同樣的,並且你們都知道static的用法,就是在類被加載的同時該singleton對象就已經被建立,後期不會再被建立,就算後期本身又調用了getInstance()方法,但底層仍是公用的一個Singleton對象.spa
一樣,我寫了一個普通的類,來同時建立兩個對象,而且打印他們的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()); }
由此可看出來對象的字符串表示形式是不同的
public class Singleton1 { private Singleton1() {} private static final Singleton1 single = new Singleton1(); //靜態工廠方法 public static Singleton1 getInstance() { return single; } }
由於這自己就是static修飾的方法,因此是在類加載的時候被建立,後期不會再改變,因此線程是安全的。