單例模式介紹
所謂類的單例模式設計,就是採起必定的方法保證在整個系統中,對某個類只能存在一個對象實例,而且該類只提供一個取得其對象實例的方法(靜態)java
單例模式經常使用實現方式
餓漢式
步驟以下:安全
- 構造方法私有化
- 類內建立對象(建立就進行實例化)
- 向外提供一個靜態公共方法
public class SingletonTest01 { public static void main(String[] args) { Singleton st=Singleton.getInstance();//類裝載時便進行實例化 Singleton st2=Singleton.getInstance(); System.out.println(st==st2); System.out.println(st.hashCode()); System.out.println(st2.hashCode()); } } class Singleton{ //餓漢式 //1.構造器私有化 private Singleton() { } //2.本類內部建立對象實例 private final static Singleton instance =new Singleton(); //3。提供一個公有靜態方法 public static Singleton getInstance() { return instance; } }
優勢:線程安全(實現同步)
缺點:傳參數困難,且容易形成內存浪費(裝載即實例,可是有可能用不到)
多線程
懶漢式
步驟以下:spa
- 構造方法私有化
- 類內建立對象
- 向外提供一個靜態公共方法(須要判斷是否非空)
public class SingletonTest03 { public static void main(String[] args) { System.out.println("線程不安全!!!!"); Singleton st=Singleton.getInstance();//類裝載時便進行實例化 Singleton st2=Singleton.getInstance(); System.out.println(st==st2); System.out.println(st.hashCode()); System.out.println(st2.hashCode()); } } class Singleton{ private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if(instance==null) instance=new Singleton(); return instance; } }
優勢:延遲加載
缺點:線程不安全(多線程下,若一個線程進入了if(singleton==null)判斷語句塊,還將來得及往下執行,另外一個線程也經過了這個判斷語句,這時便會產生多個實例)
線程
同步方法
synchronized同步方法,每一次只容許一個線程訪問。設計
public class SingletonTest04 { public static void main(String[] args) { Singleton st=Singleton.getInstance(); Singleton st2=Singleton.getInstance(); System.out.println(st==st2); System.out.println(st.hashCode()); System.out.println(st2.hashCode()); } } class Singleton{ private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { //此方法效率低下 if(instance==null) instance=new Singleton(); return instance; } }
優勢:解決了線程不安全的問題
缺點:效率過低(每一個線程在想得到類的實例的時候,執行getInstance()方法都要進行同步。其實只執行一次代碼實例化就足夠了。)
code
同步代碼塊
class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if(instance==null) { synchronized(Singleton.class) { instance=new Singleton(); } } return instance; } }
寫法錯誤,同步並不能起到真正的做用,實際開發不可用。對象
雙重檢查
class Singleton{ private static volatile Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if(instance==null)//解決了效率低下 { synchronized(Singleton.class) { if(instance==null)//雙重檢查,實現一次實例化 { instance=new Singleton(); } } } return instance; } }
實現了延時加載,與線程安全,同時保證了效率。內存
靜態內部類
class Singleton { private static volatile Singleton instance; private Singleton() { } //外類裝載不會立刻裝載的 private static class SingletonInstance{ private static final Singleton Instance=new Singleton();//餓漢式 } //用到他的時候才裝載(JVM裝載時線程安全) public static synchronized Singleton getInstance() { return SingletonInstance.Instance;//懶漢式 } }
優勢:開發
- 這種方法採用了類裝載的機制來保證初始化實例時只有一個線程。
- 靜態內部類在Singleton進行裝載時並不會當即實例化,而是在須要進行實例化時,調用getInstance()方法,纔會裝載SingletonInstance類,從而完成實例化。
- 類的靜態屬性只會在第一次加載類的時候初始化,JVM保證了線程的安全,在類進行初始化時,別的線程是沒法進入的。
這種方法也實現了延時加載與線程安全。
枚舉方式
public class SingletonTest08 { public static void main(String[] args) { Singleton st=Singleton.Instance; Singleton st2=Singleton.Instance; System.out.println(st==st2); System.out.println(st.hashCode()); System.out.println(st2.hashCode()); } } enum Singleton{ //枚舉實現單利 Instance;//屬性 public void sayOK() { System.out.println("ok~"); } }
優勢: 枚舉方式實現單例,不只可以避免多線程同步問題,並且還能防止反序列化從新建立新的對象。