package java_study; public class HungerySingletonDemo { //1.私有化構造器 private HungerySingletonDemo() {} //2.實例化對象(餓漢) private static HungerySingletonDemo instance = new HungerySingletonDemo(); //3.提供獲取方法 public static HungerySingletonDemo getInstance() { return instance; } }
package java_study; public class LazySingletonDemo { // 1.私有化構造器 private LazySingletonDemo() { } // 2.聲明對象(餓漢) private static LazySingletonDemo instance = null; // 3.提供獲取方法並實例化,使用判斷是否單例 public static LazySingletonDemo getInstance() { if (instance == null) { instance = new LazySingletonDemo(); } return instance; } }
因爲懶漢式存在多個線程調用同一個對象資源,存在線程不安全問題,須要使用同步機制來解決該問題
餓漢模式不存在線程安全問題,在加載類的時候就實例化對象了java
// 3.提供獲取方法並實例化,使用判斷是否單例 synchronized public static LazySingletonDemo getInstance() { if (instance == null) { instance = new LazySingletonDemo(); } return instance; }
能解決線程安全問題,但因爲synchronized的做用域過大,應當使用雙重檢查加鎖緩存
雙重檢查加鎖,進入getInstance方法先不一樣步,先判斷實例是否存在,若是不存在執行一次同步代碼塊,之後再也不執行保證了安全性,又不會使性能受過大的影響安全
// 2.聲明對象(餓漢),使用volatile 該資源不會被本地線程緩存,資源直接共享內存,保證了多個線程能正確處理該資源 private static volatile LazySingletonDemo instance = null; // 3.提供獲取方法並實例化,使用判斷是否單例 public static LazySingletonDemo getInstance() { if (instance == null) { //多個線程有可能同時進入這個位置,仍然會建立多個實例,若是線程存在,之後都不會執行同步代碼塊了 synchronized (LazySingletonDemo.class) {//因爲該方法是靜態方法,同步鎖是 類.class //所以須要再次判斷 if (instance == null) { instance = new LazySingletonDemo(); } } } return instance; }