幾種單例模式總結

我的博客地址https://home.cnblogs.com/u/wdfwolf3/。轉載註明出處,謝謝。面試

  面試被要求寫一個單例模式,想不起來雙重鎖的寫法,就寫了一個普通的餓漢模式。簡單問題沒答好,面試減去不少分數。回來翻看筆記,從新過了一遍,在博客中整理記錄一下。安全

1.懶漢式,線程不安全app

public class Lazy {
    private static Lazy instance;
    private Lazy(){}

    public static Lazy getInstance() {
        if (instance == null)
            instance = new Lazy();
        return instance;
    }
}

2.懶漢式,線程不安全ide

public class Lazy {
    private static Lazy instance;
    private Lazy(){}

    public static synchronized Lazy getInstance() {
        if (instance == null)
            instance = new Lazy();
        return instance;
    }
}

3.餓漢式,線程安全 函數

public class Hungry {
    private static Hungry instance = new Hungry();
    private Hungry (){}
    public static Hungry getInstance() {
        return instance;
    }
}

4.雙重校驗鎖,線程安全優化

  因爲線程安全的懶漢式在任什麼時候候只能有一個線程調用 getInstance() 方法,可是同步操做只須要在第一次建立單例實例對象時才被須要,因此它並不高效。這就出現了雙重檢驗鎖來解決這個問題。爲何在同步塊內要檢驗兩次,由於可能會有多個線程一塊兒進入同步塊外的 if,若是在同步塊內不進行二次檢驗的話,阻塞的線程得到鎖以後又會new一個新的對象,就會生成多個實例了。spa

 

public class DoubleLock {
    private volatile static DoubleLock instance;

    private DoubleLock() {
    }

    public static DoubleLock getSingleton() {
        if (instance == null)
            synchronized (DoubleLock.class) {
                if (instance == null)
                    instance = new DoubleLock();
            }
        return instance;
    }
}

 

  這裏對instance使用了volatile關鍵字,主要是用它的禁止指令重排序功能。new Singleton()並不是是一個原子操做,在 JVM 中作了下面 3 件事情,線程

  a.給 instance 分配內存code

  b.調用 Singleton 的構造函數來初始化成員變量orm

  c.將instance對象指向分配的內存空間(執行完這步 instance 就爲非 null 了)

  JVM可能將語句c優化到語句b以前,當一個線程執行完c沒有執行b,而後釋放鎖,另一個線程得到鎖,此時判斷instance!=null,直接返回,那就會出錯。

5.靜態內部類,線程安全

public class Inner {
    private static class SingletonHolder {
        private static final Inner INSTANCE = new Inner();
    }

    private Inner() {
    }

    public static final Inner getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

6.枚舉,線程安全

public enum SingletonEnum {
    INSTANCE;
}

 

 

1、懶漢式,線程不安全

相關文章
相關標籤/搜索