首先先明白我們爲什麼要使用單例模式?
1. 減少我們 new 類實例化的次數,可以偷點懶,一般使用在那種總是得new 調用的類,如調網絡訪問接口什麼的
2. 節約內存,減少無謂的GC消耗,並且使應用可以正常運作
以上基本上就是使用單例模式的目的了,自我理解,大神有磚請輕拍。
單例模式使用,網上搜搜,就五種:
1)標準原始的單例模式的構造方式
public class Singleton {
private static Singleton instance=null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
PS:Singleton的靜態屬性instance中,只有instance爲null的時候才創建一個實例,構造函數私有,確保每次都只創建一個,避免重複創建。
缺點:只在單線程(只被一個地方使用)的情況下正常運行,在多線程(同時多個地方使用)的情況下,就會出問題(如內存泄漏)。例如:當兩個線程同時運行到判斷instance是否爲空的if語句,並且instance確實沒有創建好時,那麼兩個線程都會創建一個實例。
因爲上述的缺點,所以機智程序員,又想出一個可以多線程使用的方式解決
2)俗稱懶漢式
public class Singleton {
private static Singleton instance=null;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
PS:在解法一的基礎上加上了同步鎖,使得在多線程的情況下可以用。
缺點:上面的做法很簡單,就是將整個獲取實例的方法同步,這樣在一個線程訪問這個方法時,其它所有的線程都要處於掛起等待狀態,倒是避免了剛纔同步訪問創造出多個實例的危險,只能說,這樣的處理方式也是是夠糟的,因爲這樣會造成很多無謂的等待。
因爲上述的缺點,所以機智程序員,又想出一個避免時間等待的方法
3)雙重鎖方式
public class Singleton {
private static Singleton instance=null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
PS:這種做法與上面那種粗暴的同步做法相比就要好很多了,因爲我們只是在當前實例爲null,也就是實例還未創建時才進行同步,否則就直接返回,這樣就節省了很多無謂的線程等待時間,值得注意的是在同步塊中,我們再次判斷了Singleton是否爲null
缺點:用雙重if判斷,複雜,容易出錯。
4)餓漢式
public class Singleton {
private static Singleton instance=new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
PS:初試化靜態的instance創建一次。如果我們在Singleton類裏面寫一個靜態的方法不需要創建實例,它仍然會早早的創建一次實例。而降低內存的使用率。
缺點:這種方式最主要的缺點就是一旦我訪問了Singleton的任何其他的靜態域,就會造成實例的初始化,而事實是可能我們從始至終就沒有使用這個實例,造成內存的浪費。
不過在有些時候,直接初始化單例的實例也無傷大雅,對項目幾乎沒什麼影響,比如我們在應用啓動時就需要加載的配置文件等,就可以採取這種方式去保證單例。
鑑於上述方式還是有點缺陷,因此繼續出現一種解決方案
5)靜態內部類方式
public class Singleton {
private Singleton(){
}
private static class SingletonHolder{
private final static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
PS:
好了,進行到這裏,單例模式的自我優化之路算是完成了。最終的產物就是如上述的形式。上述形式保證了以下幾點。
1.Singleton最多隻有一個實例,在不考慮反射強行突破訪問限制的情況下。
2.保證了併發訪問的情況下,不會發生由於併發而產生多個實例。
3.保證了併發訪問的情況下,不會由於初始化動作未完全完成而造成使用了尚未正確初始化的實例。