3 回答

TA貢獻(xiàn)2016條經(jīng)驗(yàn) 獲得超9個(gè)贊
第一個(gè)是延遲加載,第二個(gè)是急切加載。也許您的應(yīng)用程序從不調(diào)用單例,因此如果創(chuàng)建單例的新實(shí)例是消耗大量資源的操作,那么延遲加載會(huì)更好,因?yàn)樗鼤?huì)在需要時(shí)創(chuàng)建新實(shí)例。

TA貢獻(xiàn)1846條經(jīng)驗(yàn) 獲得超7個(gè)贊
您使用的第一種方法不是線程安全的。我會(huì)認(rèn)為這是一個(gè)錯(cuò)誤。
第二種方法更簡(jiǎn)單、線程安全、快速,并且如果您確保構(gòu)造函數(shù)不會(huì)拋出愚蠢的異常,則正確。
如果您絕對(duì)需要更多邏輯,您可以使用第一種方法,必須確保使用互斥鎖保護(hù)它。就像是:
public class MySingleton {
private static final Object mylock = new Object();
private static MySingleton instance;
public static MySingleton getInstance() {
synchronized(mylock) {
if (instance == null) {
instance = new MySingleton();
}
return instance;
}
}
}
顯然代碼更復(fù)雜,使用更多內(nèi)存,速度更慢,你不能將變量聲明為 final ...
這兩種方法都會(huì)懶惰地初始化 Singleton。在 Java 中,所有變量初始化和靜態(tài)構(gòu)造函數(shù)都在使用類時(shí)由類加載器參與,而不是在代碼開(kāi)始時(shí)。如果您的代碼路徑從不調(diào)用 getInstance,則 Singleton 將永遠(yuǎn)不會(huì)被初始化。
就個(gè)人而言,我避免使用單例,但是當(dāng)我使用它們時(shí),總是在變量聲明上立即分配。
更正 我進(jìn)行了一些實(shí)驗(yàn),結(jié)果發(fā)現(xiàn)類初始化與主線程的執(zhí)行并行發(fā)生。它沒(méi)有等待,就像我相信的那樣。至少在一個(gè)非常簡(jiǎn)化的測(cè)試場(chǎng)景中,初始化是急切的,但是是異步的。

TA貢獻(xiàn)1828條經(jīng)驗(yàn) 獲得超3個(gè)贊
這兩種實(shí)現(xiàn)單例的方式在功能上有什么區(qū)別嗎?
是的。如果在變量聲明中使用初始化器,則在初始化類時(shí)會(huì)創(chuàng)建實(shí)例,即使該實(shí)例從未被訪問(wèn)過(guò)。如果您在getInstance()
方法中對(duì)其進(jìn)行初始化,則僅在訪問(wèn)該實(shí)例時(shí)才創(chuàng)建該實(shí)例。這具有線程安全隱患。如果初始化實(shí)例很便宜并且沒(méi)有持久的外部副作用,那么它并沒(méi)有太大的區(qū)別,但情況可能并非總是如此。
第一種方法在技術(shù)上是否表現(xiàn)更好,因?yàn)樗辉诘谝淮涡枰獣r(shí)才被初始化,而不是在程序啟動(dòng)時(shí)?
如果您要在任何情況下使用實(shí)例,那么無(wú)論如何您都將在某個(gè)時(shí)候支付初始化它的成本,因此在這個(gè)意義上沒(méi)有性能差異。但是,第一種方法的線程安全版本在第一次調(diào)用時(shí)會(huì)比第二種方法稍微貴一些,并且您將在每次后續(xù)調(diào)用時(shí)再次支付額外的開(kāi)銷。
添加回答
舉報(bào)