單例模式

使用懶漢式加載。 最終能夠作到 線程安全,延遲加載,效率高的特色。java

package oneDay;

/**
 * 保證一個類僅有一個實例,並提供一個訪問它的全局訪問點
 * 1:構造方法私有化
 * 2:聲明一個本類對象
 * 3:給外部提供一個靜態方法獲取對象實例
 * <p>
 * <p>
 * 單例設計模式的存在是爲了什麼?
 * 1:在設計一些工具類的時候,不須要屬性這些東西,只須要方法就能夠,因此就不摻和對象,只用單例就能夠.
 * 2:工具類可能會被頻繁調用.
 * 目的是爲了節省重複建立對象所帶來的內存消耗.從而提升效率.
 * <p>
 * 能不能使用構造方法私有化再加上static 來替代單例?   不能, 構造方法 不能靜態化.
 * <p>
 * <p>
 * 在類被加載的時候 由於類中的實例是有 static修飾的,因此當時的實例已經建立好了.
 * 而後繼續getIntance的時候  獲得的就是 同一個對象.
 */
public class singleCase {
    public static void main(String[] args) {

    }
}


// 餓漢式 : 在類被加載後,對象被建立,到程序結束以後釋放.
class Singleton1 {
    private Singleton1() {
    }

    private static Singleton1 s = new Singleton1();

    public static Singleton1 getInstance() {
        return s;
    }

    public void print() {
        System.out.println("測試方法1!");
    }
}
// 懶漢式  : 在第一次調用getInstance方法時,對象被建立,到程序結束後釋放.
// 在多線程訪問的時候 可能會由於生命週期的問題  而出現程序崩潰錯誤.
// 可能出現 第一個線程進入 getInstance的時候, 發現s爲空 , 在沒有 聲明實例的時候, 第二個進程也發現了 s 爲空.  這個時候   實例就變了.
// 解決方法:
// 1: 將getInstance加上線程鎖, 可是這樣的話就是 串行執行了 . 效率的良心大大滴壞了.
// 2: 還有一種說話 是給 s = new Singleton2(); 加上同步代碼塊, 可是這樣顯然無法解決  實例變化的問題. 是個扯淡的方法.

class Singleton2 {
    private Singleton2() {
    }

    private static Singleton2 s;

    public static Singleton2 getInstance() {
        if (s == null)
            s = new Singleton2();
        return s;
    }

    public void print() {
        System.out.println("測試方法2!");
    }
}

// 3: 結合第二種方法, 實現第三種方法 . 加上同步代碼塊減小鎖影響的顆粒大小, 而且避免第二種方法的問題.  就是在同步代碼塊中  再次判斷是否爲空.
//  雙重加鎖法.  可是這樣還可能會存在問題.  由於牽扯到 JVM實現 s = new Singleton3(); 的指令順序問題 .
//  其指令大體分爲如下三步:   1 申請一塊內存空間用於存放實例內容 2 在該空間實例化對象  3  將該內存地址富裕s
//  底層執行的時候  不必定是按照123 執行的,  有多是132 (底層代碼速度優化方案.). 這樣的話 在沒有實例化對象的時候 , s不爲null , 這樣另外一個線程發現s 不爲空, 可是拿到的是空的s , 這個時候程序就炸了.
class Singleton3 {
    private Singleton3() {
    }

    private static Singleton3 s;

    public static Singleton3 getInstance() {
        if (s == null)
            synchronized (Singleton3.class) {
                /* 第三種方案對  對二種方法的改進 */
                if (s == null) {
                    s = new Singleton3();
                }
            }
        return s;
    }

    public void print() {
        System.out.println("測試方法2!");
    }
}
// 4: 爲了解決第三種方案的缺陷,  咱們須要禁止代碼重排. 由此而生第四種方案, 這個應該是最完美的方案了.
class Singleton4 {
    private Singleton4() {
    }

    /* 第四種方案對第三種的優化 */
    private static volatile Singleton4 s;

    public static Singleton4 getInstance() {
        if (s == null)
            synchronized (Singleton4.class) {
                /* 第三種方案對  對二種方法的改進 */
                if (s == null) {
                    s = new Singleton4();
                }
            }
        return s;
    }

    public void print() {
        System.out.println("測試方法2!");
    }
}

使用餓漢式配合類裝載機制,也能夠實現懶加載和線程安全,以及高效。設計模式

public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

類加載器加載類的時候,會將靜態屬性直接初始化。 經過這裏類加載器的特性, 咱們能夠作到線程安全。 經過內部類的方式,實現懶加載。安全

相關文章
相關標籤/搜索