1. 程式人生 > >單例模式(java程式碼實現)

單例模式(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();
    }
}