單例的應用場景:java
須要頻繁的建立和銷燬對象的、建立對象時耗時過多或者消耗資源過多可是又常常用到的對象、工具類對象或數據庫或文件的對象。數據庫
當對象含有可改變的狀態時(更精確的說就是在實際應用中該狀態會改變),則用多例。安全
1、懶漢式,線程安全的實現函數
public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }
這雖然是線程安全的,可是效率低。還有一些比較常犯的錯誤,不加同步限制的,不作舉例。工具
2、餓漢式,線程安全spa
1.構造器私有化線程
2.類的內部建立對象code
3.像外部暴露一個靜態的公共方法。getInstance對象
優勢:在類裝載的時候就完成了實例化。避免了線程同步問題。blog
缺點:沒有達到Lazy Loading(懶加載)的效果,若是歷來沒使用過這個類,就會形成內存的浪費。
public class Singleton{
//類加載時就初始化
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
可是要是明確要求是須要懶加載的,這個就不行的
第二種寫法,在類的靜態代碼塊中建立實例:
public class Singleton { //1.構造函數私有化 private Singleton() { } //2.在本類的內部建立對象實例 private static Singleton instance; static { instance = new Singleton(); } //3.提供靜態方法,返回實例對象 public static Singleton getInstance() { return instance; } }
3、靜態內部類
我比較傾向於使用靜態內部類的方法,這種方法也是《Effective Java》上所推薦的。
public class Singleton { |
4、枚舉
用枚舉寫單例實在太簡單了!這也是它最大的優勢。下面這段代碼就是聲明枚舉實例的一般作法。
public enum EasySingleton{ |
建立enum時,編譯器會自動爲咱們生成一個繼承自java.lang.Enum的類,咱們上面的enum能夠簡單看做:
class Type extends Enum{ public static final Type A; public static final Type B; ... }
demo:
public enum SingleEnum { INSTANCE; private static String[] strings = {"1", "2"}; public String[] getStrings() { return strings; } }
5、雙重檢測
//雙重檢查 public class Singleton {
private static volatile Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
這個代碼只在第一次,兩個線程不能同時執行synchronized方法,可是,後面install不爲空後,instance == null就直接pass掉了。volatile的做用理解是instance = new Singleton當即到內存中生效。