Java—关于单例模式的实现方式
1.餓漢式(線程安全,調用效率高,但是不能延時加載):JVM初始化的時候創建對象,不能延時
public class Singleton { private static Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }2.懶漢式(線程安全,調用效率不高,但是能延時加載):
public class Singleton {//類初始化時,不初始化這個對象(延時加載,真正用的時候再創建)private static Singleton instance;private Singleton(){}public static synchronized Singleton getInstance(){if(instance==null){instance=new Singleton();}return instance;} }3.靜態內部類實現方式(線程安全,調用效率高,可以延時加載):
public class Singleton {private Singleton() {}private static class SingletonHolder{private static final Singleton singleton = new Singleton();}public static Singleton getInstance(){return SingletonHolder.singleton;}}如果多個線程同時去初始化一個類,那么只會有一個線程去執行這個類的類構造器,其他線程都需要阻塞等待,直到活動線程執行方法完畢。
特別需要注意的是,在這種情形下,其他線程雖然會被阻塞,但如果執行方法的那條線程退出后,其他線程在喚醒之后不會再次進入/執行方法,因為在同一個類加載器下,一個類型只會被初始化一次。如果在一個類的方法中有耗時很長的操作,就可能造成多個線程阻塞,在實際應用中這種阻塞往往是隱藏的。
4.枚舉類(線程安全,調用效率高,不能延時加載,可以天然的防止反射和反序列化調用):
枚舉就是在一個類里定義幾個靜態變量,每個變量都是這個類的實例。
public enum Singleton {//枚舉元素本身就是單例INSTANCE;//添加自己需要的操作public void singletonOperation(){} }5.雙重檢查鎖 DCL
public class Singleton {private static [volatile] Singleton instance = null;private Singleton (){}public static Singleton getInstance(){if(instance == null) { synchronized (Singleton.class) {if(instance == null) {instance = new Singleton();}}}return instance;} }鎖之前判斷是為了優化,提高性能。鎖是為了防止多線程同時申請到多個實例。
但是卻有一個致命的缺陷,那就是初始化對象并不是一個原子操作,
instance = new Singleton();
為了提高性能,編譯器和處理器常常會對指令進行重排序。重排序分為三種:編譯器重排序,指令級并行重排序,內存系統重排序,實現優化,優化結果可能是
也可能是這樣
如果是第二種情況,在多線程情況下第一個線程已經進入了instance = new Singleton?(); 正在初始化,此時已經將Singleton?對象的地址賦給instance變量,但是Singleton?對象仍為初始化完畢。導致對象的某些屬性為空的情況。
解決方法:instance變量加上,重排序限制,也就是volatile。
總結
以上是生活随笔為你收集整理的Java—关于单例模式的实现方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 寄生式创业更容易成功
- 下一篇: C语言的整型溢出问题