概念
單例模式即一個 JVM 記憶體中隻存在一個類的對象執行個體。

分類
1、懶漢式
使用的時候才建立執行個體
2、餓漢式
類加載的時候就建立執行個體
當然還有其他的生成單例的方式,雙重校驗鎖,枚舉和靜态内部類,文中會有介紹。
懶漢式
1) 示例1
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
線程不安全,不可用。
2) 示例2
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
同步方法,線程安全,效率低,不推薦。
3) 示例3
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
線程不安全,會産生多個執行個體,不可用。
餓漢式
無線程安全問題,不能延遲加載,影響系統性能。
4) 示例1
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
5) 示例2
public class Singleton {
private static Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
6) 雙重校驗鎖
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
雙重校驗鎖,線程安全,推薦使用。
7) 靜态内部類
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
靜态内部類,線程安全,主動調用時才執行個體化,延遲加載效率高,推薦使用。
8) 枚舉
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
枚舉類型,無線程安全問題,避免反序列華建立新的執行個體,很少使用。
注意事項
1、考慮多線程問題
2、單例類構造方法要設定為private類型禁止外界new建立
private Singleton() {}
3、如果類可序列化,考慮反序列化生成多個執行個體問題,解決方案如下
private Object readResolve() throws ObjectStreamException {
// instead of the object we're on, return the class variable INSTANCE
return INSTANCE;
}
使用場景
1、工具類對象
2、系統中隻能存在一個執行個體的類
3、建立頻繁或又耗時耗資源且又經常用到的對象
下面是單例模式在JDK的應用
另外,Spring 容器中的執行個體預設是單例餓漢式類型的,即容器啟動時就執行個體化 bean 到容器中,當然也可以設定懶漢式 defalut-lazy-init="true" 為延遲執行個體化,用到時再執行個體化。