做業18:單例模式

一 什麼是單例?

顧名思義就是單個實例html

當你開出來的摸具,並使用摸具產生惟一一個模型,這就是單例。java

而單例模式就是爲了保證該類只產生一個實例。併發

二 何時須要單例?

簡單說,你不須要多個實例的時候,就能夠使用單例。工具

工具類通常都定義爲單例,由於工具類不須要那麼多個實例。線程

單例的好處:code

  • 節省維護對象的開銷:建立、內存佔用、回收
  • 實例狀態易於維護,注:通常單例不維護狀態,當多個線程進行更改狀態時,會產生併發問題。

三 如何實現單例?(不考慮序列化、反射)

1 餓漢式

public class Singleton{
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

2 懶漢式

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

3 靜態內部類

public class Singleton {
    private Singleton() {}

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }

    static class SingletonHolder {
        private static final Singleton instance = new Singleton3();
    }
}

4 枚舉

public enum  Singleton {
    instance;
}

注:枚舉本質上就是餓漢模式,具體參考做業16:java枚舉類的祕密htm

四 單例補充

1 考慮反射

  • 暴力反射能打破private限制,從而調用構造方法來建立對象。
public class Main {
    public static void main(String[] args) throws Exception{
        Class<? extends Singleton> aClass = Singleton.getClass();
        Constructor<? extends Singleton> constructor = aClass.getDeclaredConstructor();
        constructor.setAccessible(true); // 暴力反射
        Singleton singleton = constructor.newInstance();
        System.out.println(singleton == Singleton.getInstance()); // false
    }
}

// 以餓漢爲例的解決方案:構造器中拋出異常,防止對象建立成功
public class Singleton{
    private static final Singleton instance = new Singleton();

    private Singleton() {
        if (instance != null)
            throw new RuntimeException("private constructor");
    }

    public static Singleton getInstance() {
        return instance;
    }
}

2 考慮序列化

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 序列化
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("singleton.txt")));
        oo.writeObject(Singleton.getInstance());
        oo.close();

        // 反序列化
        ObjectInputStream oi = new ObjectInputStream(new FileInputStream(new File("singleton.txt")));
        Singleton singleton = (Singleton) oi.readObject();
        oi.close();

        System.out.println(singleton == Singleton.getInstance()); // false
    }
}

// 以餓漢爲例的解決方案:添加readResolve方法
public class Singleton implements Serializable {
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }

    private Object readResolve() {
        return instance;
    }
}

參考資料:對象

相關文章
相關標籤/搜索