單例模式(Singleton)是java中一個比較常見的設計模式,單例對象主要是爲了保證在一個JVM中,該對象只有一個實例存在。主要優點:java
(1) 減小一些大型對象的開銷,減小內存的佔用面試
(2) 省去了new操做,較少了GC的壓力設計模式
(3) 保證了一些核心類只被建立一次,好比一些核心的調度類,一些主要的操做類只被建立一次。安全
單例模式最多見的兩種實現模式:餓漢式,懶漢式,內部靜態類實現,雙重檢驗鎖模式函數
1.餓漢式:在進行類加載時就建立好 (添加了synchronized保證了線程的安全性)優化
package designPatterns; public class SingletonHungry { private static SingletonHungry instance = new SingletonHungry(); //私有構造函數,防止被實例化 private SingletonHungry(){ } public static SingletonHungry getInstance(){ return instance; } }
2. 懶漢式:延遲加載,在用到的時候才進行建立spa
package designPatterns; public class SingletonLazy { private static SingletonLazy instance = null; //私有構造函數,防止被實例化 private SingletonLazy(){ } public static SingletonLazy getInstance(){ if(instance == null){ instance = new SingletonLazy(); } return instance; } }
固然懶漢模式是線程不安全的,爲了保證線程安全,咱們能夠將函數定義成synchronized的,可是實際上,並非每次都須要同步的,只是在第一次建立對象的時候須要確保同步,所以咱們能夠只同步一個對象。以下線程
package designPatterns; public class SingletonLazy { private static SingletonLazy instance = null; //私有構造函數,防止被實例化 private SingletonLazy(){ } /* public static SingletonLazy getInstance(){ if(instance == null){ instance = new SingletonLazy(); } return instance; } */ public static SingletonLazy getInstance(){ if(instance == null){ synchronized(instance){ if(instance == null){ instance = new SingletonLazy(); } } } return instance; } }
可是,因爲java中建立對象和賦值操做是分開進行的,也就是說instance = new SingletonLazy()這句話是分步執行的。JVM的即時編譯存在指令重派的優化,2,3步的操做是沒法肯定的。設計
1. 給instance分配內存code
2. 調用構造函數初始化成員變量
3. 將instance對象指向分配的內存空間(執行完這句話以後instance纔會變成非null的)
兩步執行的,可能先執行分配空間,再初始化,這也可能會致使A,B兩個線程不一樣步,因此還有一種方法是使用內部靜態類來進行實現,內部靜態類在另外一篇博客中有詳細介紹,這裏再也不贅述。
3. 靜態內部類,代碼以下:
package designPatterns; public class Singleton { //私有構造方法,防止被實例化 private Singleton(){ } //靜態內部類建立實例 private static class SingletonFactory{ private static Singleton instance = new Singleton(); } //獲取實例 public static Singleton getInstance(){ return SingletonFactory.instance; } //若是該對象被用於序列化,能夠保證對象在序列化先後保持一致 public Object readResolve(){ return getInstance(); } }
使用內部靜態類的方法,只有在外部類被調用時纔會被加載,而後new一個實例,這樣就避免了鎖的應用,通常建議使用這種方法,但仍是須要根據實際須要來進行選擇的。
4. 雙重檢驗鎖模式(雖然內部類的方法感受更加好用一些,可是不少面試官想讓你寫的仍是雙檢鎖模式)
public class Singleton { private volatile static Singleton instance; //volatile的可見性 private Singleton() {} public static Singleton getSingleton() { if(instance == null) { //Single Check synchronized(Singleton.class) { if(instance == null) { //Double Check instance = new Singleton(); } } } return instance; } }
雙檢鎖模式其實就是爲了保證一個順序。雙檢鎖的出現保證了上述2,3句的執行順序。