7種方式實現單例模式

2021-09-10 05:32:10 字數 2592 閱讀 8911

單例模式,即是整個類有且只有乙個類例項,通過這個唯一的例項為全域性提供服務。單例類的構造方法為私有的,通過乙個暴露給外界的獲取例項方法來呼叫私有構造方法,保證例項的唯一性。

// 因為餓漢式單例在類載入時就初始化了唯一的例項(且只會初始化一次,所以,該例項是唯一的,即	執行緒安全的),因此,如果我們想要為例項設定一些引數或配置時,將變得很困難。這就是其侷限性

public class singleton

public static singleton getinstance()

}

public class singleton 

// 當多執行緒併發時,無法保證例項的唯一性。為了保證執行緒安全,可以為方法或**塊加上synchronized關鍵字

public static singleton getinstance()

return minstance;

}}

使用了同步後,是執行緒安全了,但是效率卻也變低了。因為每次執行緒獲取例項時,都要進行方法或**塊的同步準備。(使用synchronized關鍵字是比較耗時的)為了不那麼耗時,我們可以使用dcl(二次檢查鎖定)

public class singleton 

// 第一種,為方法加上synchronized關鍵字

public synchronized static singleton getinstance()

return minstance;

} public static singleton getinstance()

}return minstance;

}}

dcl其實是有問題的。因為jvm記憶體模型(jmm)允許『無序寫入』。即在jvm執行指令過程中,指令的執行順序有可能是亂序的。如**minstance = new singleton();其實這行**做了3件事:

1,為單例物件分配記憶體空間

2,將minstance引用變數指向剛分配好的記憶體空間(此時,minstance已經是非null的了)

3,為單例物件通過minstance呼叫其類的構造方法進行初始化。

在jvm執行過程中,2,3步的執行順序是不確定的,可能是顛倒的。顛倒的情況下,在併發時,就有可能發生嚴重的錯誤,當執行緒一執行到步驟2而未執行步驟3時(例項未初始化,但引用變數minstance已經非null),如果此時被執行緒2獲取到了cpu的使用權,執行緒2在執行minstance的非null判斷時,將會認為minstance為非null而直接返回引用,但其實此時是未初始化的,如果執行緒2使用這個minstance引用,系統就會報錯(因為minstance未初始化卻被使用了)。

在jdk版本較高(>1.5)的情況下,可以通過使用volatile關鍵字來避免這種情況

public class singleton 

// 為什麼會不那麼耗時暱?因為我們除了在第一次建立例項時進行了**塊的同步準備外,其他的訪問,會在第一次判斷時就會返回(此時例項已不為null),不會進行同步準備,而是直接返回了例項,所以提高了效率

public static singleton getinstance()

}

}return minstance;

}}

public class singleton 

public static singleton getinstance() catch(exception e) {}

if (temp != null)

// 為什麼要做這個看似無用的操作,因為這一步是為了讓虛擬機器執行到這一步的時才會對singleton賦值,

// 虛擬機器執行到這裡的時候,必然已經完成類例項的初始化。所以這種寫法的dcl是安全的。由於try的存在,虛擬機器無法優化temp是否為null

// 這裡需要了解try關鍵字

minstance = temp;

}}

}return minstance;

}}

// 因為通過靜態內部類實現,當某個執行緒要獲取例項時,return singletonholder.instance這個語句會通知jvm進行內部類的載入(只會載入一次,這意味著instance變數會且只會被初始化一次,所以是執行緒安全的)。當例項被首次初始化後,其他執行緒訪問的將會是同乙個例項

// 類載入發生在需要的時候。通俗地講,只有在程式執行到需要某個類的時候(如讀取某個屬性值),才會進行該類的載入。所以,當乙個類被載入時,它的內部類不會被同時載入。

public class singleton

private singleton(){}

public static singleton getinstance()

}

// 單元素的列舉類。

// 使用列舉實現單例模式可以避免通過反射以及反序列化破壞單例的問題

public enum enumsingleton

}

參考文章:

單例模式、雙檢測鎖定dcl、volatile**)

高併發下執行緒安全的單例模式(最全最經典)

單例模式的7種實現方式

多個執行緒要操作同乙個物件,保證物件的唯一性,例項化過程只例項化一次 解決的思路 在載入類時就例項化乙個物件 public class singleton1 public static singleton1 getintance 特點用這個物件的時候才去例項化 public class hoonsi...

單例模式的7種實現方式及比較

多個執行緒要操作同一物件,需要保證物件的唯一性。為了更好的對下面即將介紹的幾種實現方式進行比較,我們定義幾個考量維度 執行緒的安全線 是否懶載入 效能。方法一 餓漢式單例模式 可用 public class badmashsingleton public static badmashsingleto...

單例模式(5種實現方式)

1.餓漢式 不支援併發 此模式只能執行在單執行緒下,且類在載入時就已經建立好了例項,不管需不需要用。package com.lys 餓漢式 public class singleton1 private static singleton1 instance new singleton1 public...