設計模式之單例模式

實現方式

共三種:

  1. 餓漢式
  2. 懶漢式
  3. 枚舉單例
  4. 靜態內部類式 (推薦)

餓漢式

原理:類在初始化加載的時候,會加載內部 靜態 成員對象,然後方法被調用的時候,直接返回這個對象
/**
* 測試餓漢式單例模式
* @author 尚學堂高淇 www.sxt.cn
*
*/
public class Demo {
    private Demo(){}; //私有化構造器
    private static Demo demo = new Demo();  //類初始化時,立即加載這個對象(沒有延時加載的優勢)。加載類時,天然的是線程安全的!
    public  static Demo getInstance(){     //方法沒有同步,調用效率高!
        return demo;
    }
}

懶漢式

原理:方法被外部調用的時候,先判斷對象是否被實例化,如果沒有,則實例化返回,如果有 直接返回  該方法需要加同步鎖synchronized,
/**
* 測試懶漢式單例模式
*/
public class Demo {
    private Demo(){};
    private static Demo demo;
    public  static synchronized Demo getInstance(){  //方法同步,調用效率低!
        if(demo == null){
            demo = new Demo();
        }
        return demo;
    }
}

枚舉單例

優點:
    1.實現簡單
    2.枚舉本身就是單例模式。由JVM從根本上提供保障 避免通過反射和反序列化的漏洞
缺點:
    1.無延遲加載

/**
* 測試枚舉式實現單例模式(沒有延時加載)
*/
public enum SingletonDemo5 {
    
    //這個枚舉元素,本身就是單例對象!
    INSTANCE;
    
    //添加自己需要的操作!
    public void singletonOperation(){
    }
}

靜態內部類式 推薦

1.沒有靜態 內部 成員對象 所以和餓漢式不一樣
2.靜態內部類,在調用的時候初始化 懶
3.內部類中成員對象是 static final 保證了在內存中只有一份實例,


/**
* 測試靜態內部類實現單例模式
* 這種方式:線程安全,調用效率高,並且實現了延時加載!
* @author 尚學堂高淇 www.sxt.cn
*
*/
public class Demo {

    private Demo(){};

    //靜態內部類
    private static class DemoInstance {
        private static final Demo instance = new Demo();
    }

    public static Demo getInstance(){
        return DemoInstance.instance;
    }
}

比較

主要

  1. 餓漢式(線程安全,調用效率高,但是 不能延時加載)
  2. 懶漢式 (線程安全,調用效率不高,但是 可以延時加載) 每次調用getInstance() 方法都要同步,併發效率太低
  3. 靜態內部類式(線程安全,調用效率高。可以延時加載)
  4. 枚舉單例(線程安全,調用效率高,不能延時加載)

測試效率

/**
* 測試多線程環境下五種創建單例模式的效率
*/
public class Client3 {
    
    public static void main(String[] args) throws Exception {
        
        long start = System.currentTimeMillis();
        int threadNum = 10;
        final CountDownLatch  countDownLatch = new CountDownLatch(threadNum);
        
        for(int i=0;i<threadNum;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    
                    for(int i=0;i<1000000;i++){
//                      Object o = SingletonDemo4.getInstance();
                        Object o = SingletonDemo5.INSTANCE;
                    }
                    countDownLatch.countDown();
                }
            }).start();
        }
        
        countDownLatch.await();    //main線程阻塞,直到計數器變爲0,纔會繼續往下執行!
        
        long end = System.currentTimeMillis();
        System.out.println("總耗時:"+(end-start));
    }
}
發佈了143 篇原創文章 · 獲贊 76 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章