天天看點

Java筆記:單例模式

什麼是單例模式呢?就是在整個系統中,隻有一個唯一存在的執行個體。使用singleton的好處還在于可以節省記憶體,因為它限制了執行個體的個數,有利于java垃圾回收。

單例模式主要有3個特點:

1、單例類確定自己隻有一個執行個體。

2、單例類必須自己建立自己的執行個體。

3、單例類必須為其他對象提供唯一的執行個體。

單例模式的實作方式有五種方法:懶漢,惡漢,雙重校驗鎖,枚舉和靜态内部類。

這種寫法能夠在多線程中很好的工作,而且看起來它也具備很好的<code>lazy loading</code>,但是,遺憾的是,效率很低,99%情況下不需要同步。

這種方式基于classloder機制避免了多線程的同步問題,但是沒有達到<code>lazy loading</code>的效果。

當兩個線程執行完第一個 <code>singleton == null</code> 後等待鎖, 其中一個線程獲得鎖并進入synchronize後,執行個體化了,然後退出釋放鎖,另外一個線程獲得鎖,進入又想執行個體化,會判斷是否進行執行個體化了,如果存在,就不進行執行個體化了。

首先,其他類在引用這個singleton的類時,隻是建立了一個引用,并沒有開辟一個的堆空間存放(對象所在的記憶體空間)。接着,當使用<code>singleton.getinstance()</code>方法後,java虛拟機(jvm)會加載<code>singletonholder.class</code>(jls規定每個class對象隻能被初始化一次),并執行個體化一個singleton對象。

缺點:需要在java的另外一個記憶體空間(java permgen 永久代記憶體,這塊記憶體是虛拟機加載class檔案存放的位置)占用一個大塊的空間。

這種方式是effective java作者josh bloch 提倡的方式,它不僅能避免多線程同步問題,而且還能防止反序列化重新建立新的對象。

通過這種方式,不能通過反射和序列化來擷取一個執行個體,因為所有的枚舉類都繼承自java.lang.enum類, 而不是object類:

其他需要注意的事項:

如果singleton實作了<code>java.io.serializable</code>接口,使用反序列化可以生成一個新的對象,這樣需要重寫readresolve方法,傳回靜态的單個執行個體。

單例模式在 java 标準庫中的使用:

<code>java.lang.runtime#getruntime()</code>是 java 标準庫中常用的方法,它傳回與目前java應用關聯的運作時對象。