java中單例模式是一種常見的設計模式,單例模式分爲三種:懶漢式單例、惡漢式單例和登記式單例。java
單例模式有如下特色設計模式
一、單例只能有一個實例安全
二、單例必須本身建立本身的惟一實例多線程
三、單例必須給其餘對象提供惟一實例app
懶漢式單例線程
public class Singleton { private static Singleton single = new Singleton(); private Singleton(){}//私有化構造器 public static Singleton getInstance() { return single; } }
餓漢式單例設計
public class Singleton { private static Singleton single = null; private Singleton(){} public static Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; } }
在單線程環境下,上面的惡漢式不存在任何問題,但在多線程環境下,線程A和B,線程A第一次進入判斷single爲null,而後CPU切換到線程B,B判斷single也爲null,此時B線程會執行new Singleton(),而後CPU切回線程A,線程A繼續執行也會new Singleton(),此時就會出現兩個實例,問題就出來了。code
考慮到多線程環境下多線程安全問題,高效的餓漢式修改以下cdn
public class Singleton { private static Singleton single = null; private Singleton(){} public static Singleton getInstance() { //旨在避免實例化後其它線程在進入這個方法後進入同步代碼塊,提升效率 if (single != null) { return single; } synchronized (Singleton.class) { //第一個線程進入同步代碼塊,多個線程等待拿同步代碼塊的鎖,進入同步代碼塊 //當第一個線程實例化,離開同步代碼塊後 //其它等待拿同步所的線程依次進入能夠直接返回實例化對象 if (single != null) { return single; } single = new Singleton(); } return single; } }
若是須要進一步提升效率能夠拋棄同步代碼塊使用Lock鎖對象
public class Singleton { private static Singleton single = null; private Singleton(){} public static Singleton getInstance() { //旨在避免實例化後其它線程在進入這個方法後進入同步代碼塊,提升效率 if (single != null) { return single; } ReentrantLock lock = new ReentrantLock(false); try { lock.lock(); if (single != null) { return single; } single = new Singleton(); } catch (Exception e) { System.err.println(e.getMessage()); } finally { lock.unlock(); } return single; } }
登記式單例
等級是單例這個單例實際上維護的是一組單例類的實例(父類和子類),講這些實例存放在一個Map(登記薄)中,對於已經登記過的實例,則從Map中獲取直接返回,對於沒有登記的,則先登記,再返回。
@SuppressWarnings("unchecked") public class Singleton { @SuppressWarnings("rawtypes") private static HashMap map = new HashMap(); private Singleton (){} static { Singleton single = new Singleton(); map.put(single.getClass().getName(), single); } public static Singleton getInstance(String name) { if (name == null) { name = "Singleton"; } if (map.get(name) == null) { try { map.put(name, Class.forName(name).newInstance()); } catch (Exception e) { System.out.println("Error happened."); } } return (Singleton) map.get(name); } }
其子類實現
public class SingletonChild extends Singleton { private SingletonChild(){} public static SingletonChild getInstance() { return (SingletonChild) Singleton.getInstance("SingletonChild"); } }