單例設計模式所解決的問題就是:保證類的對象在內存中唯一。
1、餓漢
/**
* @說明:餓漢模式
* 解決思路:
* 1.不允許其他程序使用new創建該類對象。(別人new不可控)
* 2.在該類中創建一個本類實例。
* 3.對外提供一個方法讓其他程序可以獲取該對象。
* 步驟:
* 1.私有化該類的構造函數
* 2.通過new在本類中創建一個本類對象。
* 3.定義一個共有的方法將創建的對象返回。
* @author heyanpeng
*/
public class Single {
private final static Single sigle = new Single();
// 私有化構造函數
private Single () {
}
public static Single getInstance(){
return sigle;
}
}
2、懶漢
/**
* @說明:懶漢模式
* 延遲對象創建,第一次使用的時候創建,節省了內存空間
* 存在的弊端:多線程編程中,使用懶漢式可能會造成類的對象在內存中不唯一
*
* @author heyanpeng
*/
public class Single2 {
private static Single2 single2 = null;
// 私有化構造函數
private Single2(){
}
public static Single2 getInstance(){
if (null == single2) {
single2 = new Single2();
}
return single2;
}
}
總結:
懶漢式在面試的時候經常會被提到,因爲知識點比較多,而且還可以和多線程結合起來綜合考量。
餓漢式在實際開發中使用的比較多。
3、懶漢式多線程優化
/**
* @說明:懶漢多線程優化
* 在懶漢模式下,if(null == single2) 的判斷存在線程安全
*
* @author heyanpeng
*/
public class Single3 {
private static Single3 single3 = null;
// 私有化構造函數
private Single3(){
}
/**
* 方案1: 方法增加synchronized同步
*/
public static synchronized Single3 getInstance(){
if (null == single3) {
single3 = new Single3();
}
return single3;
}
/**
* 方案2: 代碼塊增加synchronized同步
*/
public static Single3 getInstance2(){
synchronized(Single3.class){
if (null == single3) {
single3 = new Single3();
}
return single3;
}
}
/**
* 方案3: 爲空的時候加synchronized同步,再進行爲空判斷
*/
public static Single3 getInstance3(){
if (null == single3) {
synchronized(Single3.class){
if (null == single3) {
single3 = new Single3();
}
}
}
return single3;
}
}
總結:假設我們現在並沒有創建單例對象,即snull,那麼我們調用getInstance方法的時候,會進入if塊,然後進入同步代碼塊,此時,別的線程如果想要創建Single實例,就必須獲取鎖;等當前線程創建完實例對象,釋放鎖之後,假設正巧有幾個線程已經進入了if塊中,它們會拿到鎖,進入同步代碼塊,但是由於進行了判空操作,所以不會創建Single實例,而是直接返回已經創建好的Single實例。如果有多個其他線程進入了if塊,當它們依次進入同步代碼塊的時候,同理也不會創建新的Single實例。而沒有進入if塊的線程,判空操作之後不滿足條件,進不了if塊,而直接執行了下一條語句return s;其後的線程調用getInstance方法時,只會判斷一次snull,不滿足條件直接返回Single單例s,這樣就大大提高了了執行效率。
第一行代碼是第一次判空操作,目的是提高效率;第三行代碼是同步代碼塊的入口,目的是保證線程安全;第五行代碼進行第二次判空操作是爲了保證單例對象的唯一性。