小議Java中幾種Singleton模式實現的優劣

2021-06-21 23:45:30 字數 3534 閱讀 5826

本文根據自身的學習和使用,總結出了5種實現singleton的方法,並對他們的優缺點進行了簡單的總結。

第一種:最常用型,**如下

public class singleton1 

private static singleton1 instance=null;

private singleton1()

public static synchronized singleton1 getinstance()

system.out.println("thread : "+thread.currentthread().getname()+" getting instance!");

return instance;

}}

這種實現,直接對getinstance函式增加了同步關鍵字,因此可以保證instance任何情況下,只被建立一次,但是有個問題,就是每次對getinstance的呼叫都會去試圖獲取該同步鎖,這就增加了程式執行開銷,而且,如果第一次呼叫已經建立了instance之後,則後續的呼叫實質上已經不需要再去獲取同步鎖,而只需要判斷instance是否為null即可。因此,這種方法,雖然實現了同步控制,但同步的粒度太大,影響了程式執行的效能。

第二種:對第一種的改造,降低同步粒度

public class singleton2 

private static integer flag = 0;

private static singleton2 instance=null;

private singleton2()

public static singleton2 getinstance()

}} return instance;

}}

可以看出,上面這種實現,直接在getinstance函式裡面增加同步塊,這樣的話,當第一次獲取到同步鎖後,instance被建立,

後面再對getinstance的呼叫,首先判斷instance是否為null,如果非null,則無需再去獲取同步鎖,這樣的話,就大大降低了等待獲取同步鎖的開銷,另外,即便是有多個執行緒同時進入getinstance函式,並且同時判斷instance為null,那麼第乙個獲得同步鎖的執行緒建立了instance後,並釋放同步鎖,第二個執行緒獲得了同步鎖,發現instance非null,則不做任何事,釋放同步鎖。也比第一種效率要高些,這裡在網上看到有人直接用synchronized(instance)來實現同步控制是不正確的,因為synchronized()中不能對空物件進行操作,否則會丟擲 nullpointerexception異常。

第三種:通過靜態類成員類實現

這種實現方式的理論基礎是,instance的建立在類的載入中完成,而jvm中類的載入是執行緒互斥的,因此,可以自動保證instance只建立一次。**如下:

public class singleton3 

private static singleton3 instance= new singleton3();

private singleton3()

public static singleton3 getinstance() }

public class testthread implements runnable

}輸出:

thread : thread-0 creating instance!

thread : thread-0 getting instance!

thread : thread-1 getting instance!

從輸出結果可以看出,在singleton3類的載入過程中,其static成員instance已經被建立,而且由於類的載入是執行緒互斥的,所以,可以保證instance只能被建立一次,

這種實現的好處是,無需由使用者自己去增加同步控制來實現instance的建立,但是,缺點是,如果這裡的instance物件如果是個比較大的object,則在類載入時就要對其

建立,而不是到了使用的時候才建立,會增加程式執行的效能開銷。針對這種問題,我們可以採用靜態內部類來實現延遲建立,這就是第四種實現方式。

第四種:靜態內部類實現

public class singleton4 

private static class singletonfactory

private singleton4()

public static singleton4 getinstance() }

輸出:thread : thread-0 getting instance!

thread : thread-1 getting instance!

thread : thread-0 creating instance!

從輸出結果可以看出,singleton4中的singletonfactory中的instance,並不是在類載入過程中就建立了,而是在呼叫getinstance中的singletonfactory.instance才真正建立instance,這就達到了用時建立的延遲建立的目的,即,程式執行過程中,如果不用instance,則就不去建立,降低了執行開銷。

第五種:對第二種的改進

public class singleton5 

private singleton5()

private static singleton5 instance=null;

private static synchronized void createinstance() }

public static singleton5 getinstance()

return instance;

}}

即,將第二種方法中的同步塊提出來作為乙個單獨的函式,之所以這樣做,原因如下,試想如下情形:在第二種實現中,執行緒a進入了同步塊,判斷instance為null,執行instance=new singleton2(),jvm為instance分配空間,並把找個空間賦值給instance,稍後某個時候才對分配的記憶體進行初始化,a執行完同步塊,這時,執行緒b在等待同步塊,並進入同步塊,判斷instance非null,然後退出並返回instance的引用,這時由於instance的記憶體空間還沒有被jvm進行初始化,因此後面的呼叫就可能出現異常。而,把同步塊單獨提出來作為乙個單獨的函式,則在某種意義上就會避免這種情形的發生,因為在createinstance()函式退出時,jvm一定是已經對instance的空間進行了初始化。這個原因是我個人的理解,稍後打算花一定時間去研究jvm物件的初始化,因為,我個人感覺jvm的物件初始化機制和**所在塊有關,第二種的同步塊是一段**,第五種實現中是個同步函式,這二者的差異可能會影響到jvm對物件初始化的時間。

以上是本人對singleton的理解和總結,有不當之處,還需要牛人們多多指正。

Java設計模式 單例模式(single)

目錄目的 應用例項 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。菜鳥教程 乙個國家有乙個首都 windows 是多程序多執行緒的,在操作乙個檔案的時候,就不可避免地出現多個程序或執行緒同時操作乙個檔案的現象,所以所有檔案的處理必須通過唯一的例項來進行。第一種 package com.ga...

Java 中幾種查詢演算法

順序查詢 說明 順序查詢適合於儲存結構為順序儲存或鏈結儲存的線性表。int sequelsearch elemtype s,keytype key,int n 在s 0 s n 1 中順序查詢關鍵字為key的記錄 查詢成功時返回該記錄的下標序號 失敗時返回 1 二分查詢 1 遞迴方法實現 int b...

小議ArcMap面轉線的幾種方式

arcmap是乙個功能豐富的複雜系統,但凡對它有些認知的會同意這個觀點。它的豐富與複雜體現在乙個objective有多種implementation,還體現在多種implementation有類似的result。分析這些同與不同,可以幫助我們更好地認識與綜合運用這個系統。這裡,博主單拎出 面轉線 這...