單例模式(java代碼實現)

應用單例模式時,類只能有一個對象實例,這麼做的目的是避免不一致狀態。

餓漢式單例:(立即加載)

// 餓漢式單例
public class Singleton1 {

    // 指向自己實例的私有靜態引用,主動創建
    private static Singleton1 singleton1 = new Singleton1();

    // 私有的構造方法
    private Singleton1(){}

    // 以自己實例爲返回值的靜態的公有方法,靜態工廠方法
    public static Singleton1 getSingleton1(){
        return singleton1;
    }
}

懶漢式單例:(延遲加載)

// 懶漢式單例
public class Singleton2 {

    // 指向自己實例的私有靜態引用
    private static Singleton2 singleton2;

    // 私有的構造方法
    private Singleton2(){}

    // 以自己實例爲返回值的靜態的公有方法,靜態工廠方法
    public static Singleton2 getSingleton2(){
        // 被動創建,在真正需要使用時纔去創建
        if (singleton2 == null) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

 

多線程下線程安全的懶漢式單例(餓漢式本身是線程安全的):

1)、同步延遲加載 — synchronized方法

// 線程安全的懶漢式單例
public class Singleton2 {

    private static Singleton2 singleton2;

    private Singleton2(){}

    // 使用 synchronized 修飾,臨界資源的同步互斥訪問
    public static synchronized Singleton2 getSingleton2(){
        if (singleton2 == null) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

 

2)、同步延遲加載 — synchronized塊

// 線程安全的懶漢式單例
public class Singleton2 {

    private static Singleton2 singleton2;

    private Singleton2(){}


    public static Singleton2 getSingleton2(){
        synchronized(Singleton2.class){  // 使用 synchronized 塊,臨界資源的同步互斥訪問
            if (singleton2 == null) { 
                singleton2 = new Singleton2();
            }
        }
        return singleton2;
    }
}

3)、同步延遲加載 — 使用內部類實現延遲加載

// 線程安全的懶漢式單例
public class Singleton5 {

    // 私有內部類,按需加載,用時加載,也就是延遲加載
    private static class Holder {
        private static Singleton5 singleton5 = new Singleton5();
    }

    private Singleton5() {

    }

    public static Singleton5 getSingleton5() {
        return Holder.singleton5;
    }
}

 

4)雙重檢測

// 線程安全的懶漢式單例
public class Singleton3 {

    //使用volatile關鍵字防止重排序,因爲 new Instance()是一個非原子操作,可能創建一個不完整的實例
    private static volatile Singleton3 singleton3;

    private Singleton3() {
    }

    public static Singleton3 getSingleton3() {
        // Double-Check idiom
        if (singleton3 == null) {
            synchronized (Singleton3.class) {       // 1
                // 只需在第一次創建實例時才同步
                if (singleton3 == null) {       // 2
                    singleton3 = new Singleton3();      // 3
                }
            }
        }
        return singleton3;
    }
}

 

5)ThreadLocal

public class Singleton {

    // ThreadLocal 線程局部變量,將單例instance線程私有化
    private static ThreadLocal<Singleton> threadlocal = new ThreadLocal<Singleton>();
    private static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {

        // 第一次檢查:若線程第一次訪問,則進入if語句塊;否則,若線程已經訪問過,則直接返回ThreadLocal中的值
        if (threadlocal.get() == null) {
            synchronized (Singleton.class) {
                if (instance == null) {  // 第二次檢查:該單例是否被創建
                    instance = new Singleton();
                }
            }
            threadlocal.set(instance); // 將單例放入ThreadLocal中
        }
        return threadlocal.get();
    }
}

 


引用《徹頭徹尾理解單例模式與多線程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章