單例模式確保某個類只有一個實例,並且自行實例化並向整個系統提供這個實例。在計算機系統中,線程池、緩存、日誌對象、對話框、打印機、顯卡的驅動程序對象常被設計成單例。這些應用都或多或少具備資源管理器的功能。每臺計算機能夠有若干個打印機,但只能有一個Printer Spooler,以免兩個打印做業同時輸出到打印機中。每臺計算機能夠有若干通訊端口,系統應當集中管理這些通訊端口,以免一個通訊端口同時被兩個請求同時調用。總之,選擇單例模式就是爲了不不一致狀態,避免政出多頭。java
那就讓咱們看看幾種常見的單例模式吧。緩存
//懶漢式單例類.在第一次調用的時候實例化本身 public class Singleton { private Singleton() {} private static Singleton single=null; //靜態工廠方法 public static Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; } }
應該是你們寫的比較多的了,可是這種寫法的時候在多線程的時候就會出現問題,因而就引出了下面兩種寫法安全
一、在getInstance方法上加同步多線程
public static synchronized Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; }
二、雙重檢查鎖定ide
public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; }
可是上面這兩種加了同步鎖的單例在效率方便又不是很高,因而又有改進的方式了性能
public class Singleton { private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return LazyHolder.INSTANCE; } }
這種靜態內部類實現的單例,既實現了線程安全,又避免了同步帶來的性能影響。線程
其實還有不少種單例模式,咱們再往下面看看設計
//餓漢式單例類.在類初始化時,已經自行實例化 public class Singleton1 { private Singleton1() {} private static final Singleton1 single = new Singleton1(); //靜態工廠方法 public static Singleton1 getInstance() { return single; } }
這個就是所謂的餓漢式單例,在類建立的同時就已經建立好一個靜態的對象供系統使用,之後再也不改變,因此天生是線程安全的。日誌
彆着急還有兩種也是我才見到的code
一、枚舉單例
public enum Singleton { INSTANCE { @Override protected void read() { System.out.println("read"); } @Override protected void write() { System.out.println("write"); } }; protected abstract void read(); protected abstract void write(); }
枚舉單例很簡單就作到了1.線程安全 2.不會由於序列化而產生新實例 3.防止反射攻擊
二、利用AtomicReference來實現
public class Singleton { private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>(); private Singleton (){} public static Singleton getInstance() { for (;;) { Singleton current = INSTANCE.get(); if (current != null) { return current; } current = new Singleton(); if (INSTANCE.compareAndSet(null, current)) { return current; } } } }
看到這個我都蒙圈了。
具體怎麼取選擇單例模式的實現就看你們本身了