一、 單例模式概述
Java中單例模式的定義是:一個類只有一個實例,而且自行實例化並且向整個系統提供這個實例。
優點:由於單例模式在內存中只有一個實例,減少了內存開支和系統的性能開銷;單例模式可以避免對資源的多重占用。
二、單例模式的幾種形式
1. 餓漢式單例
public class Singleton {
private static final Singleton singleton= new Singleton();
private Singleton(){
}
public Singleton getSingleton(){
return singleton;
}
}
餓漢式是線程安全的,在類開始加載的時候就完成了單例的初始化。線程安全在java並發編程實戰中是這樣定義的:當多個線程訪問某個類時,不管運行時環境采用何種調度方式或者這些線程將如何交替執行,並且在主調代碼中不需要任何額外的同步或者協同,這個類都能表現出正確的行為,那麼就稱這個類是線程安全的。
2.懶漢式單例
public class Singleton {
private Singleton() {}
private static Singleton single=null;
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
懶漢式不是線程安全的,並發環境下,可能出現多個single對象。要實現線程安全,可以采用雙重鎖:
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
三、單例模式在spring中的應用
DefaultSingletonBeanRegistry類中的getSingleton方法:
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// map緩存中查看是否存在實例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
從上面的代碼中可以看出spring在獲取單例bean的時候,采用了雙重判斷加鎖的單例模式,首先嘗試從map緩存singletonObjects中獲取實例,如果獲取不到,對singletonObjects加鎖,再到map緩存earlySingletonObjects裡面獲取,如果還是為null,就創建一個bean,並放到earlySingletonObjects中去。