單例模式(Singleton Pattern)是一個比較簡單的模式,它保證一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。
通用代碼:
<pre name="code" class="java"><span style="font-size:14px;">public class Singleton{
private static final Singleton singleton = new Singleton();
private Singleton(){}//私有構造函數,使其無法類外通過new構造
public static Singleton getSingleton(){
return singleton;
}
public static void doSomething(){}//類中其他方法,儘量爲static
}</span>
單例模式通過private的構造函數確保只產生一個自行實例化的對象。
這種單例在類加載時就初始化單例,然而有時初始化單例代價比較高,希望在使用時才加載,這時可以使用Lazy loading方式的單例模式:
<pre name="code" class="java">public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
} <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<pre name="code" class="java"> public static void doSomething(){}//類中其他方法,儘量爲static
}
這種方式是Singleton類被裝載了,instance不一定被初始化。因爲SingletonHolder類沒有被主動使用,只有顯示通過調用getInstance方法時,纔會顯示裝載SingletonHolder類,從而實例化instance。
單例模式在內存只有一個實例,減少了內存開銷,也可以避免對資源的多重佔用。不過單例模式一般沒有抽象,擴展困難,而且也與單一職責原則衝突。
單例模式擴展,有上限多例模式:
<pre name="code" class="java">public class Singleton{
private static int manNum = 2;
private static ArrayList<Singleton> singleton = new ArrayList<Singleton>();
static{
for(int i = 0; i < manNum; i ++){
singleton.add(new Singleton());
}
private Singleton(){}//私有構造函數,使其類外無法通過new構造
public static Singleton getSingleton(int countNum){
return singleton.get(countNum);
}
public static void doSomething(){}//類中其他方法,儘量爲static
}
使用單例模式需要注意JVM的垃圾回收機制,如果單例對象在內存中長久不使用,JVM就會認爲這個對象是一個垃圾,在CPU資源空閒情況下會被清理掉,下次調用產生新的單例對象,如果單例類有狀態值,則會出現異常。可以使用兩種方法來避免:1.由容器管理單例的生命週期,如使用Spring可以使對象常駐內存。2.狀態隨時記錄,使用異步記錄的方法或觀察者模式,保存狀態的變化,確保單例重新初始化時可以獲得銷燬前數據。