標籤:方法區 線程 null lazy 記憶體 color 執行 系統 獲得
單例模式,是一種常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中,應用該模式的類一個類只有一個執行個體。即一個類只有一個對象執行個體。
在JAVA中實現單例,必須瞭解JAVA記憶體機制,JAVA中執行個體對象存在於堆記憶體中,若要實現單例,必須滿足兩個條件:
1.限制類執行個體化對象。即只能產生一個對象。
2.保證外部能夠擷取這個對象,否則對象建立將毫無意義
如要滿足以上兩個條件,可以將構造方法私人化,然後在類中提供一個靜態方法擷取類執行個體。代碼如下
1 public class SingleTon { 2 3 private static final SingleTon single = new SingleTon(); 4 5 private SingleTon() { 6 7 } 8 9 /**10 * 擷取一個單例對象。11 * @return 返回SingleTon對象。12 */13 public static SingleTon getInstance() {14 return single;15 }16 17 }
JVM載入SingleTon後,會對靜態成員做預設初始化,此時new SingleTon()建立的對象會賦值給single,類只會被載入一次,即使多次調用getInstance方法,所返回的對象也不會改變。single欄位在初始化的過程中,對象就建立了,所以以上案例的代碼又稱為餓漢式。從對象的生命週期來看,類一旦載入,對象會在堆中立即建立,會浪費記憶體空間,因此,又存在另外一種稱為懶漢式的單例設計模式。代碼如下:
1 public class SingleTonLazy { 2 3 private static SingleTonLazy single = null; 4 5 private SingleTonLazy() { 6 7 } 8 9 /**10 * 擷取一個單例對象。11 * @return 返回SingleTon對象。12 */13 public static SingleTonLazy getInstance() {14 15 if (single == null) {16 single = new SingleTonLazy();17 }18 19 return single;20 21 }22 23 }
SingleTonLazy在被載入進方法區後,不會立即建立對象,而是直到getInstance方法被調用以後,對象才會被建立。這種方式可以節約記憶體空間,但是也存在著安全執行緒問題,當線程A執行到判斷對象為null,此時線程B獲得執行權,線程B判斷對象為null,此時線程A重新獲得執行權,建立對象,線程B恢複,繼續建立對象。將代碼修改如下,使用同步鎖解決安全執行緒問題。
1 public class SingleTonLazy { 2 3 private static SingleTonLazy single = null; 4 5 private final static Lock lock = new ReentrantLock(); 6 7 private SingleTonLazy() { 8 9 }10 11 /**12 * 擷取一個單例對象。13 * @return 返回SingleTon對象。14 */15 public static SingleTonLazy getInstance() {16 17 if (single != null) {18 return single;19 }20 21 lock.lock();22 if (single == null) {23 single = new SingleTonLazy();24 }25 lock.unlock();26 27 return single;28 29 }30 }
總結:餓漢式與懶漢式各有優缺點,但是相對來說,佔用記憶體空間比讓cpu判斷鎖的開銷要小,所以餓漢式更使用一些。
JAVA設計模式之單例設計模式