別再用懶漢模式了 從JVM的角度看單例模式

2021-09-13 09:23:13 字數 1711 閱讀 8589

我們先來看看網上普遍的結論:

所謂「懶漢式」與「餓漢式」的區別,是在與建立單例物件的時間的不同。

「懶漢式」是在你真正用到的時候才去建這個單例物件

「餓漢式是在類建立的同時就已經建立好乙個靜態的物件,不管你用的用不上,一開始就建立這個單例物件

先不說結論,看看下文

餓漢式

public

class

singleton1

public

static singleton1 getsingleton (

)}

在類靜態變數裡直接new乙個單例

懶漢式
public

class

singleton2

public

static singleton2 getinstance ()}

}return singleton;

}}

**1 處的判空是為了減少同步方法的使用,提高效率

**2,3 處的加鎖和判空是為了防止多執行緒下重複例項化單例。

**5 處的volatile是為了防止多執行緒下**4 的指令重排序

測試方法

建立乙個test測試類

public

class

test

}

從結果上看沒啥毛病,那我們來加個斷點試試。按照以往的認知,餓漢單例是在類載入的時候的例項化,那麼執行main方法應該會輸出餓漢單例的初始化,我們來看看結果:

public

static

void

main

(string[

] args)

throws ioexception

此時執行結果:

如圖是沒有結果的,餓漢單例怎麼沒有例項化呢?原來餓漢單例是在本類載入的時候才例項化的,在斷點的時候還沒有載入餓漢單例。

我們來詳細複習一下類載入:

類的載入分為5個步驟:載入、驗證、準備、解析、初始化

初始化就是執行編譯後的()方法,而()方法就是在編譯時將靜態變數賦值和靜態塊合併到一起生成的。

所以說,「餓漢模式」的建立物件是在類載入的初始化階段進行的,那麼類載入的初始化階段在什麼時候進行呢?jvm規範規定有且只有以下7種情況下會進行類載入的初始化階段:

綜上,基本來說就是只有當你以某種方式呼叫了這個類的時候,它才會進行初始化,而不是jvm啟動的時候就初始化,而jvm本身會確保類的初始化只執行一次。那如果不使用這個單例物件的話,記憶體中根本沒有singleton例項物件,也就是和「懶漢模式」是一樣的效果。

當然,也有一種可能就是單例類裡除了getinstance()方法還有一些其他靜態方法,這樣當呼叫其他靜態方法的時候,也會初始化例項,但是這個很容易解決,只要加個內部類就行了:

public

class

singleton

public

static singleton getinstance (

)}

網上的結論普遍說單例過早占用資源,而推薦使用「懶漢模式」,但他們忽略了單例何時進行類載入,經過以上分析,「懶漢模式」實現複雜而且沒有任何獨佔優點,「餓漢模式」完勝。「餓漢模式」使用場景推薦:

別再用offset和limit分頁了

終於要對mysql優化下手了,本文將對分頁進行優化說明,希望可以得到乙個合適你的方案 分頁這個話題已經是老生常談了,但是有多少小夥伴一邊是既希望優化的自己的系統,另一邊在專案上還是保持自己獨有的個性。優化這件事是需要自己主動行動起來的,自己搞測試資料,只有在測試的路上才會發現更多你未知的事情。本文咔...

求求你別再用offset和limit分頁了

不需要擔心資料庫效能優化問題的日子已經一去不復返了。隨著時代的進步,隨著野心勃勃的企業想要變成下乙個 facebook,隨著為機器學習 收集盡可能多資料的想法的出現,作為開發人員,我們要不斷地打磨我們的 api,讓它們提供可靠和有效的端點,從而毫不費力地瀏覽海量資料。如果你做過後台開發或資料庫架構,...

單例模式 懶漢模式

在實際應用中,我們往往希望在使用的時候才進行類的載入,而不希望類初始化的時候就進行載入,所以單例模式又有了另外一種實現,懶漢模式 一.延遲載入 如下 public class myobject public static myobject getinstance return myobject 延遲...