爲何說單例模式性價比高?
在面試過程當中常常讓手擼的一種設計模式,而且被面的頻率很是高。重點是這種設計模式很簡單!java
個人我的博客(後臺建站,Tomcat集羣,Redis分佈式,nginx,適合初學者)nginx
爲何要用單例模式?面試
在開發過程當中,根據需求的不一樣,有時可能要求對象實例只能有一個,這時就要使用到了單例模式。設計模式
如:Spring中的bean默認使用的都是單例模式。安全
什麼是單例模式?cookie
確保對象只有一個,並提供一個全局訪問點。分佈式
經典的實現方式:性能
餓漢式線程
public class Singleton1{ private static Singleton1 uniqueInstance = new Singleton1(); private Singleton1() { super(); } public static Singleton1 getInstance(){ return uniqueInstance; } }
懶漢式設計
public class Singleton2{ private static Singleton2 uniqueInstance = null; private Singleton2(){ super(); } public static Singleton2 getSinleton(){ if (uniqueInstance == null) { uniqueInstance = new Singleton2(); } return uniqueInstance; } }
進階實現方式
雙重檢查加鎖
public class Singleton3{ private static volatile Singleton3 uniqueInstance = null; private Singleton3 (){ super(); } public static Singleton3 getInstance() { if (uniqueInstance == null){ synchronized (Singleton3.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton3(); } } } return uniqueInstance; } }
靜態內部類
public class Singleton4{ private Singleton4() { super(); } private static class Holder{ private static final Singleton4 uniqueInstance = new Singleton4(); } public static final Singleton4 getInstance(){ return Holder.uniqueInstance; } }
餓漢式: 在類加載時就建立對象,不管是否使用都會建立,天生線程安全。
懶漢式:延遲化實例,在使用時纔會建立,線程不安全,相比餓漢式來講對於資源敏感的對象很重要,能節省系統資源。
雙重校驗:延遲化實例,線程安全,可是犧牲性能來提高安全。
靜態內部類:只有在,內部類在第一次調用Holder.uniqueInstance時纔會建立實例,因此也是一種延遲化實例的機制,經過靜態內部類只有第一次引用纔會被加載,因此是線程安全的;而且經過反射,也沒法從外部類獲取內部類的屬性。因此這種形式,很好的避免了反射入侵。
爲何進行雙重校驗?
因爲同步範圍比較精確,也可能出現安全問題,即在判斷爲null和加鎖之間另外一個線程已經建立了對象,由於使用了volitile關鍵字保證了對象的可見性,因此必須在此進行二次檢查,不然式去了同步的意義。
如何選擇適當的方案?
①系統是不是資源敏感型?
若是對系統資源不敏感,懶漢式式一種不錯的選擇!
②是否有性能上考慮?
若是沒有性能上考慮,可使用懶漢式!
若是有性能考慮,應使用雙重檢查加鎖或靜態內部類!
注:靜態內部類也有一些缺點,須要兩個類才能實現,雖然不會建立靜態內部類的對象,可是其 Class 對象仍是會被建立,並且是屬於永久代的對象。