標籤:-- == 反射 html 資料 for ilo 避免 target
--------------------------------------------------
目錄
1.定義
2.常見的集中單例實現
a.餓漢式,安全執行緒 但效率比較低
b.單例模式的實現:飽漢式,非安全執行緒
c.飽漢式,安全執行緒簡單實現
d.安全執行緒 並且效率高 單例模式最優方案
3.總結
a.使用枚舉的單例模式
b.使用枚舉,static處調用,初始化一次
--------------------------------------------------
1.定義
確保一個類只有一個執行個體,並提供一個全域訪問點!
2.常見的集中單例實現
a.餓漢式,安全執行緒 但效率比較低
/** * 單例模式的實現:餓漢式,安全執行緒 但效率比較低 */ public class SingletonTest { // 定義一個私人的構造方法 private SingletonTest() { } // 將自身的執行個體對象設定為一個屬性,並加上Static和final修飾符 private static final SingletonTest instance = new SingletonTest(); // 靜態方法返回該類的執行個體 public static SingletonTest getInstancei() { return instance; } }
b.單例模式的實現:飽漢式,非安全執行緒
/** * 單例模式的實現:飽漢式,非安全執行緒 * */ public class SingletonTest { // 定義私人構造方法(防止通過 new SingletonTest()去執行個體化) private SingletonTest() { } // 定義一個SingletonTest類型的變數(不初始化,注意這裡沒有使用final關鍵字) private static SingletonTest instance; // 定義一個靜態方法(調用時再初始化SingletonTest,但是多線程訪問時,可能造成重複初始化問題) public static SingletonTest getInstance() { if (instance == null) instance = new SingletonTest(); return instance; } }
c.飽漢式,安全執行緒簡單實現
/** * 單例模式的實現:飽漢式,安全執行緒簡單實現 * */ public class SingletonTest { // 定義私人構造方法(防止通過 new SingletonTest()去執行個體化) private SingletonTest() { } // 定義一個SingletonTest類型的變數(不初始化,注意這裡沒有使用final關鍵字) private static SingletonTest instance; // 定義一個靜態方法(調用時再初始化SingletonTest,使用synchronized 避免多線程訪問時,可能造成重的複初始化問題) public static synchronized SingletonTest getInstance() { if (instance == null) instance = new SingletonTest(); return instance; } }
d.安全執行緒 並且效率高 單例模式最優方案
/** * 單例模式最優方案 * 安全執行緒 並且效率高 * */ public class SingletonTest { // 定義一個私人構造方法 private SingletonTest() { } //定義一個靜態私人變數(不初始化,不使用final關鍵字,使用volatile保證了多線程訪問時instance變數的可見度,避免了instance初始化時其他變數屬性還沒賦值完時,被另外線程調用) private static volatile SingletonTest instance; //定義一個共有的靜態方法,返回該類型執行個體 public static SingletonTest getIstance() { // 對象執行個體化時與否判斷(不使用同步代碼塊,instance不等於null時,直接返回對象,提高運行效率) if (instance == null) { //同步代碼塊(對象未初始化時,使用同步代碼塊,保證多線程訪問時對象在第一次建立後,不再重複被建立) synchronized (SingletonTest.class) { //未初始化,則初始instance變數 if (instance == null) { instance = new SingletonTest(); } } } return instance; } }
3.總結
【以上單例模式】傳統的兩私人一公開(私人構造方法、私人靜態執行個體(懶執行個體化/直接執行個體化)、公開的靜態擷取方法)涉及安全執行緒問題(即使有多重檢查鎖也可以通過反射破壞單例)
目前最為安全的實現單例的方法是通過內部靜態enum的方法來實現,因為JVM會保證enum不能被反射並且構造器方法只執行一次。如下
a.使用枚舉的單例模式
/** * 使用枚舉的單例模式 * * @author yzl * @see [相關類/方法](可選) * @since [產品/模組版本] (可選) */public class EnumSingleton{ private EnumSingleton(){} public static EnumSingleton getInstance(){ return Singleton.INSTANCE.getInstance(); } private static enum Singleton{ INSTANCE; private EnumSingleton singleton; //JVM會保證此方法絕對只調用一次 private Singleton(){ singleton = new EnumSingleton(); } public EnumSingleton getInstance(){ return singleton; } }}
b.使用枚舉,static處調用,初始化一次
import java.util.ArrayList;import java.util.List;/** * 初始化的優雅實現 * 可以在static處調用, * 也可以在普通方法裡調用,都保證只初始化一次 * * 當然將enum塊的代碼直接放到StaticInitTest類的private static 方法裡做也是可以的 * * @author yzl * @see [相關類/方法](可選) * @since [產品/模組版本] (可選) */public class StaticInitTest { private static List<Integer> dataList = null; static{ dataList = Singleton.INSTANCE.init(); } /** * * 單例模式來填充資料 * * @author yzl * @see [相關類/方法](可選) * @since [產品/模組版本] (可選) */ private static enum Singleton { INSTANCE; private List<Integer> list; private Singleton(){ fillData(); } /** * * 初始化資料 * * @see [相關類/方法](可選) * @since [產品/模組版本](可選) */ private void fillData(){ list = new ArrayList<Integer>(5); for(int i =1; i<6; i++){ list.add(i); } } /** * * 初始化的入口 * * @see [相關類/方法](可選) * @since [產品/模組版本](可選) */ public List<Integer> init(){ return list; } }}
參考資料:java單例之enum實現方式
java設計模式--單例模式
Java設計模式の單例模式