java中单例的几种写法
?
- java中單例的幾種寫法
- 一單例模式常見的寫法
- 二枚舉類型實現單例模式
?
java中單例的幾種寫法
單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例。
單例通常有很多種寫法,但是性能和效果卻是差距挺大。下面列舉了幾種常見的寫法。
一、單例模式常見的寫法
1.懶漢式(線程不安全)
public class Singleton {private static Singleton instance = null;private Singlton() {}public static Singleton getInstance() {if(instance == null)return instance;return instance;} }這種寫法,在多線程的時候,由于并發訪問instance,會導致創建多個instance,從而使得單例模式失效。
2.懶漢式(線程安全1)
public class Singleton {private static Singleton instance = null;private Singlton() {}public synchronized static Singleton getInstance() {if(instance == null)return instance;return instance;} }這種寫法的優點是保證了線程安全,缺點是效率低下,因為instance一旦創建,大部分時間都是多線程在訪問instance,因此把同步加在方法上會導致多個線程等待。
3.懶漢式(線程安全2)
public class Singleton {private static Singleton instance = null;private Singlton() {}public static Singleton getInstance() {if(instance == null) {synchronized(Singleton.class) {instance = new Singleton();return instance;}} return instance;} }這種寫法有效的避免了第3種寫法的缺點,當instance被創建成功后,大部分時間多線程訪問instance的時候都無需同步;而只有當需要創建instance的時候才需要同步創建instance的代碼塊。看似這種寫法比較完美,但是這種寫法有有一個致命的缺點就是,當線程A判斷instance等于null的時候,這時線程A被掛起,線程B判斷instance為null,同時獲取到鎖進入了同步代碼塊,然后成功的創建了instance,最后釋放了鎖退出了同步代碼塊。恰好此時線程A成功的獲取到鎖進入同步代碼塊繼續執行,它也會創建一個instance,這樣instance就被創建不止一次,系統中就存在多個instance。
4.雙重檢驗式(Double Check Lock)
public class Singleton {private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if(instance == null) {synchronized(Singleton.class) {if(instance == null) {instance = new Singleton();return instance;}}} return instance;} }雙重校驗可以避免第3種方法的缺點,當線程獲得鎖后進入同步代碼塊后,再進一步確認instance是否為null。通常雙重校驗鎖這種形式會比較好的達到正常的單例的效果。
5.餓漢式
public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;} }這種方式利用ClassLoader的機制保證了單例類只在被類加載器第一次加載的時候,創建一個instance,避免了多線程的同步問題。優點是沒有同步代碼塊,效率高;缺點是Singleton可能會因為多種原因被加載,因此沒有實現懶加載。
6.餓漢式(靜態內部類)
public class Singleton {private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton() {}public static Singleton getInstance() {return SingletonHolder.INSTANCE;} }這種方式相對于第5種方式,雖然由于某種原因導致Singleton類被類加載器加載,但是由于SingletonHolder沒有被顯示的加載,因此instance還是沒有被創建。因此這種形式在某種程度上來說,相對于第5種寫法來說延遲了instance的創建。
當單例類由不同的類加載器加載或者能被序列化和反序列化或者可以通過反射來調用私有構造函數的時候,上述的幾種方式都不能很好的實現單例的效果,這個需要再進一步討論。
二、枚舉類型實現單例模式
從JDK1.5以后,可以通過枚舉類型來實現線程安全的、防止序列化和反序列化的、代碼簡潔的單例模式。
public enum Singleton {INSTANCE;//屬性private int a,b,c;//構造函數只能為私有的private Singleton() {}public void method1() {}public void method2() {} }采用這種方式實現的單例模式是十分推薦的,天然線程安全,天然解決了序列化和反序列化之后、反射調用私有構造函數出現多個對象的問題。同時這也是Effective Java推薦的寫法。
轉載于:https://www.cnblogs.com/Spground/p/8536145.html
總結
以上是生活随笔為你收集整理的java中单例的几种写法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IntelliJ IDEA常用的快捷键(
- 下一篇: Appium Python 六:管理应用