單例對象(Singleton)是一種經常使用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。java
須要使得類的一個對象成爲系統運行過程當中的惟一實例。設計模式
1)實例控制多線程
單例模式會阻止其餘對象實例化其本身的單例對象的副本,從而確保全部對象都訪問惟一實例。spa
2)靈活性線程
由於類控制了實例化過程,因此類能夠靈活更改實例化過程。設計
1)開銷code
雖然數量不多,但若是每次對象請求引用時都要檢查是否存在類的實例,將仍然須要一些開銷。能夠經過使用靜態初始化解決此問題。對象
2)可能的開發混淆內存
使用單例對象(尤爲在類庫中定義的對象)時,開發人員必須記住本身不能使用new關鍵字實例化對象。由於可能沒法訪問庫源代碼,所以應用程序開發人員可能會意外發現本身沒法直接實例化此類。開發
3)對象生存期
不能解決刪除單個對象的問題。在提供內存管理的語言中(例如基於.NET Framework的語言),只有單例類可以致使實例被取消分配,由於它包含對該實例的私有引用。在某些語言中(如 C++),其餘類能夠刪除對象實例,但這樣會致使單例類中出現懸浮引用。
//沒有達到lazy loading的效果 class HungrySingleton{ private static HungrySingleton singleton=new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){ return singleton; } }
class LazySingleton{ private static LazySingleton singleton; private LazySingleton(){ } public static LazySingleton getInstance(){ if(singleton==null){ singleton=new LazySingleton(); } return singleton; } }
//加載時不會初始化靜態變量INSTANCE,由於沒有主動使用,達到Lazy loading class InternalSingleton{ private static class SingletonHolder{ private final static InternalSingleton INSTANCE=new InternalSingleton(); } private InternalSingleton(){} public static InternalSingleton getInstance(){ return SingletonHolder.INSTANCE; } }
//《Effective Java》做者推薦使用的方法,優勢:不只能避免多線程同步問題,並且還能防止反序列化從新建立新的對象 enum EnumSingleton{ INSTANCE; public void doSomeThing(){ } }
//帶有雙重校驗鎖的單例模式 class LockSingleton{ private volatile static LockSingleton singleton; private LockSingleton(){} public static LockSingleton getInstance(){ if(singleton==null){ synchronized(LockSingleton.class){ if(singleton==null){ singleton=new LockSingleton(); } } } return singleton; } }
//相似Spring裏面的方法,將類名註冊,下次從裏面直接獲取。 class Singleton3 { private static Map<String,Singleton3> map = new HashMap<String,Singleton3>(); static{ Singleton3 single = new Singleton3(); map.put(single.getClass().getName(), single); } //保護的默認構造子 protected Singleton3(){} //靜態工廠方法,返還此類唯一的實例 public static Singleton3 getInstance(String name) { if(name == null) { name = Singleton3.class.getName(); System.out.println("name == null"+"--->name="+name); } if(map.get(name) == null) { try { map.put(name, (Singleton3) Class.forName(name).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return map.get(name); } //一個示意性的商業方法 public String about() { return "Hello, I am RegSingleton."; } public static void main(String[] args) { Singleton3 single3 = Singleton3.getInstance(null); System.out.println(single3.about()); } }