單例設計模式Singleton

單例設計模式Singleton

存在意義

  • 有些對象的創建消耗時間和內存是非常大的,恰恰好這些對象在我們的應用中只需要使用 1 個,如果不能得到控制,會造成資源的浪費。例如線程池、數據庫連接池,一個應用程序中,我們只需要有 1 個這樣的大對象。

單例模式的兩種寫法:懶漢式和餓漢式

說明

  • 餓漢式:在程序啓動或單件模式類被加載的時候,單件模式實例就已經被創建。(線程安全)
  • 懶漢式:當程序第一次訪問單件模式實例時才進行創建。(線程不安全)

如何選擇

  • 如果單件模式實例在系統中經常會被用到,餓漢式是一個不錯的選擇。

  • 如果單件模式在系統中會很少用到或者幾乎不會用到,那麼懶漢式是一個不錯的選擇。

懶漢式

/**
 * 單例懶漢式:當需要用到的時候纔會創建實例,缺點:線程不安全
 * 
 * @title
 * @description
 * @since JDK1.8
 */
public class SingleTon {

    private static SingleTon single;

       // 構造器私有化,不能在類的外部隨意創建對象
    private SingleTon() {

    }

    //重點:同步不要加在方法上,加在可能發生線程不安全的地方(寫操作而不是讀操作)
    public static SingleTon getSingleTon() {
        if (single == null) {
            // System.out.println("hello");
            synchronized (SingleTon.class) {
                if (single == null)
                    single = new SingleTon();
            }
        }
        return single;
    }

}

餓漢式

/**
 * 單例模式餓漢式:class文件被加載的時候創建實例,缺點:內存消耗大
 * 
 * @title
 * @description
 * @since JDK1.8
 */
public class SingleTon1 {

    private static SingleTon1 single = new SingleTon1();

    private SingleTon1() {

    }

    public static SingleTon1 getSingleTon1() {
        return single;
    }

}

測試類

/**
 * 單例測試類
 * @title
 * @description
 * @since JDK1.8
 */
public class Main {

    public static void main(String[] args) {
        // // 懶漢測試
        // SingleTon single1 = SingleTon.getSingleTon();
        // SingleTon single2 = SingleTon.getSingleTon();
        // System.out.println(single1 == single2);
        // // 餓漢測試
        // SingleTon1 single3 = SingleTon1.getSingleTon1();
        // SingleTon1 single4 = SingleTon1.getSingleTon1();
        // System.out.println(single3 == single4);

        // 多線程驗證懶漢式
        // for (int i = 0; i < 10; i++) {
        // Runnable run = new Runnable() {
        // @Override
        // public void run() {
        // SingleTon single5 = SingleTon.getSingleTon();
        // System.out.println(single5);
        // }
        // };
        // Thread t = new Thread(run);
        // t.start();
        // }

        Runnable run = () -> {
            //懶漢式多線程測試
            SingleTon single5 = SingleTon.getSingleTon();
            System.out.println(single5);
        };

        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(run);
            t.start();
        }
    }
}

擴展

  • 單例模式用途:
    單例模式屬於工廠模式的特例,只是它不需要輸入參數並且始終返回同一對象的引用。
    單例模式能夠保證某一類型對象在系統中的唯一性,即某類在系統中只有一個實例。它的用途十分廣泛,打個比方,我們開發了一個簡單的留言板,用戶的每一次留言都要將留言信息寫入到數據庫中,最直觀的方法是沒次寫入都建立一個數據庫的鏈接。這是個簡單的方法,在不考慮併發的時候這也是個不錯的選擇。但實際上,一個網站是併發的,並且有可能是存在大量併發操作的。如果我們對每次寫入都創建一個數據庫連接,那麼很容易的系統會出現瓶頸,系統的精力將會很多的放在維護鏈接上而非直接查詢操作上。這顯然是不可取的。
    如果我們能夠保證系統中自始至終只有唯一一個數據庫連接對象,顯然我們會節省很多內存開銷和cpu利用率。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章