3 回答

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

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

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