設計模式 | 單例模式(singleton)

定義:

保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

結構:(書中圖,侵刪)

結構超簡單。就在你想控制實例數的類上操做便可。
1.定義一個static的對象引用
2.私有化構造方法
3.提供一個獲取實例的方法(static的)
 

實例:

這又是一個在面試中頻繁出現的設計模式,我至今不知道爲何你們那麼偏心這個模式。
並且基本上都是讓你現場寫一個單例模式的例子,基於這個很現實的緣由,這個模式也好好好掌握。
我這裏就不舉生活中的例子了,直接上代碼。
 
單例模式又分爲兩種形式:
1、餓漢式:在類加載是就初始化實例。
2、懶漢式:在第一次調用的時候,才初始化實例。
 
餓漢式:
package designpattern.singleton;

public class HungrySingleton {
    private static HungrySingleton instance = new HungrySingleton();// 靜態初始化

    private HungrySingleton() {// 私有化構造方法
    }

    public static HungrySingleton GetInstance() {// 獲取實例,static的
        return instance;
    }
}
懶漢式:
package designpattern.singleton;

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {// 私有化構造方法

    }

    public static LazySingleton getInstance() {// 獲取實例,static的
        if (instance == null) {
            instance = new LazySingleton();// 方法中創造實例
        }
        return instance;
    }
}
可是,若是是在多線程的狀況下,可能會形成創造出兩個實例的狀況,能夠考慮在getInstance方法上加上synchronized修飾:
package designpattern.singleton;

public class LazySingleton2 {
    private static LazySingleton2 instance;

    private LazySingleton2() {

    }

    public static synchronized LazySingleton2 getInstance() {// synchronized 修飾
        if (instance == null) {
            instance = new LazySingleton2();
        }
        return instance;
    }
}
這個能夠進一步優化,只讓線程在尚未實例化的狀況下加鎖:
package designpattern.singleton;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LazySingleton3 {
    private static LazySingleton3 instance;
    private static Lock lock = new ReentrantLock();

    private LazySingleton3() {

    }

    public static synchronized LazySingleton3 getInstance() {
        try {
            if (instance == null) {
                lock.lock();
                if (instance == null) {// 有必要再次判斷,否則仍是存在線程安全問題
                    instance = new LazySingleton3();
                }
                lock.unlock();
            }
        } finally {// 保證鎖被釋放
            lock.unlock();
        }
        return instance;
    }
}

總結:

餓漢式,在類加載是就初始化實例,要提早佔用系統資源,可是不用考慮多線程訪問可能形成的建立多個實例的問題。
懶漢式,在第一次調用的時候,才初始化實例,不用提早佔用系統資源,可是須要考慮到多線程訪問的問題。
這個模式在全部須要控制實例數的狀況下都能使用,最多見的兩個例子,就是數據庫鏈接池和線程池。
如下緣由引用自 https://www.cnblogs.com/gmq-sh/p/5948379.html《單例模式的常見應用場景》:
數據庫鏈接池的設計通常也是採用單例模式,由於數據庫鏈接是一種數據庫資源。數據庫軟件系統中使用數據庫鏈接池,主要是節省打開或者關閉數據庫鏈接所引發的效率損耗,這種效率上的損耗仍是很是昂貴的,由於何用單例模式來維護,就能夠大大下降這種損耗。
相關文章
相關標籤/搜索