單例模式是設計模式中使用最爲普遍的模式之一。它是一種對象創建模式,用於產生一個對象的具體實例,它可以確保系統中一個類只有一個實例。這種模式有一下兩個好處:
1.對於使用頻繁地對象,可以省略new操作花費的時間。特別是對於那些重量級對象而言,能夠節省很多系統開銷。
2.由於new操作的頻率減少,系統內存的使用頻率也會降低。這將減少JVM的GC壓力。
下面來看一種單例實現
public class Singleton1{
private Singletion1{}
private static Singleton1 instance = new Singleton1();
public static Singleton getInstance(){
return instance;
}
}
創建單列模式需要注意一下幾點:
我們要把Singleton類的構造函數設置成private,這是爲了防止開發人員用過構造函數隨意創建這個類的實例。
nstance則必須是private static的,private是爲了防止instance被修改,保證其安全性;static是因爲getInstance()方法是static的。
使用以上這種實現模式能夠保證該類是單例的,但是這種實現方式有一個不足,那就是instance實例的創健時間是不受控制的。
如果想要精確控制instance的創健時間,我們可以使用中延遲加載策略,具體實現方式如下:
public class Singleton2{
private Singleton2(){}
private static Singleton2 instance = null;
public static synchronized Singleton2 getInstance(){
if (instance == null)
instance = new Singleton2();
return instance;
}
}
使用這種策略就能將instance的實例化推遲到第一次使用Singleton2的時候。注意在getInstance方法上,我們加了synchronized關鍵字,只是爲了防止在多線程下instance被多次創健。因此這種方法的缺點也就暴露出來了,那就是在競爭激烈的場合,其性能肯定會受到影響。
以上兩種方法各有好壞,那有沒有結合上述兩種方法優勢的第三中方法呢?答案肯定是有的。
public class Singleton3{
private Singleton3{
System.out.println("Singleton3 is created");
}
private static class SingletonHolder{//定義一個靜態內部類來初始化Singleton
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}
這種方法有以下2個好處:
getInstance()方法沒有加鎖,在高併發環境下具有高性能。
只有在getInstance()第一次調用的時候,纔會實例化instance。這是因爲這裏巧妙地使用了靜態內部類和類的初始化方式。
JDK1.8之後,可以使用枚舉類型來實現單例,它具有簡單、懶加載、線程安全、具有高性能等優點。代碼如下:
public enum Singleton{
INSTANCE;
public void doSomething(){
//....
}
}