文章目錄
- 一、啥是單例模式?
- 二、為什么要有單例模式,我偏不用,不服?
- 三、別磨磨蹭蹭的,阿姨!!上代碼實操如何?
- 1、餓漢式-1 -- 靜態常量
- 2、餓漢式-2 -- 靜態代碼塊
- 3、懶漢式-1 -- 執行緒不安全
- 4、懶漢式-2 --同步方法,執行緒安全
- 5、懶漢式-3 -- 同步代碼塊,執行緒不安全
- 6、懶漢式-4 --雙重檢查,執行緒安全
- 7、懶漢式-5 -- 靜態內部類,執行緒安全
- 8、列舉
- 四、測驗
- 五、來個小總結
一、啥是單例模式?
- 單例模式多種設計模式中的一種,單例模式就是在一個系統中采取一種代碼控制的手法,保證了某一個類在系統的運行程序中從始到終只有一個實體物件,
二、為什么要有單例模式,我偏不用,不服?
- 單例模式的好處:減少資源的開銷、可以讓一個單例物件實作對系統的狀態化控制,
- 很多情況系統都需要使用到單例模式,比如:
- 工具類,是不需要狀態的,它也不需要多個實體物件,單例節約創建物件的記憶體資源,
- 系統計時器,通過唯一的物件來控制系統時鐘保證系統時鐘的唯一,
三、別磨磨蹭蹭的,阿姨!!上代碼實操如何?
1、餓漢式-1 – 靜態常量
- 最簡單的單例模式,類加載時直接實體化物件,
- 優點:簡單,執行緒安全,避免執行緒同步控制,
- 缺點:無法實作懶加載,若是該物件一直不會被使用,可能會造成記憶體浪費,
*結論: 可用,可能會造成記憶體浪費,
//餓漢式(靜態變數)
class Singleton {
//1. 構造器私有化, 外部能new
private Singleton() {
}
//2.本類內部創建物件實體
private final static Singleton instance = new Singleton();
//3. 提供一個公有的靜態方法,回傳實體物件
public static Singleton getInstance() {
return instance;
}
}
2、餓漢式-2 – 靜態代碼塊
- 類加載時執行靜態代碼塊,進行物件實體化,
- 優缺點和 餓漢式-1(靜態常量) 一樣,
- 可用,可能會造成記憶體浪費,
//餓漢式(靜態變數)
class Singleton {
//1. 構造器私有化, 外部能new
private Singleton() {
}
//2.本類內部創建物件實體
private static Singleton instance;
static { // 在靜態代碼塊中,創建單例物件
instance = new Singleton();
}
//3. 提供一個公有的靜態方法,回傳實體物件
public static Singleton getInstance() {
return instance;
}
}
3、懶漢式-1 – 執行緒不安全
- 最簡單的懶漢式,呼叫
getInstance()時進行物件實體化, - 優點:懶加載的效果,
- 缺點:沒有執行緒的同步控制,多個執行緒可能同時執行到
if(instance == null),多個執行緒都可能判斷為空,這時就可能產生多個實體, - 結論:不能用,
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一個靜態的公有方法,當使用到該方法時,才去創建 instance
//即懶漢式
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
4、懶漢式-2 --同步方法,執行緒安全
- 呼叫
getInstance()時進行物件實體化,在getInstance()方法上加同步控制欄位synchronized - 優點:懶加載的效果,執行緒安全,
- 缺點:鎖的粒度較大(
synchronized作用在靜態方法,對類物件進行同步),每個執行緒都需在getInstance()外等待其他執行緒執行完getInstance(), - 結論:可用,但不推薦,
// 懶漢式(執行緒安全,同步方法)
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一個靜態的公有方法,加入同步處理的代碼,解決執行緒安全問題
//即懶漢式
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
5、懶漢式-3 – 同步代碼塊,執行緒不安全
- 思想在
getInstance()方法里面以同步代碼塊的方式進行同步,以減小鎖粒度, - 優點:鎖的粒度減小,不必要每次都對
getInstance()進行同步, - 缺點:執行緒不安全,和懶漢式-1一樣,
- 結論:不能用,
// 懶漢式(執行緒安全,同步代碼塊)
class Singleton {
private static Singleton instance;
private Singleton() {
}
//同步代碼塊,這種寫法不安全
//即懶漢式
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
6、懶漢式-4 --雙重檢查,執行緒安全
- 雙重檢查就是我們進行兩次
if (instance == null), - 優點:實作懶加載、執行緒安全、鎖粒度低、效率較高,
- 缺點:,,,,
- 結論:推薦使用,
// 懶漢式(雙重檢查,執行緒安全)
class Singleton {
private static volatile Singleton instance;
private Singleton() {}
//提供一個靜態的公有方法,加入雙重檢查代碼,解決執行緒安全問題, 同時解決懶加載問題
//同時保證了效率, 推薦使用
public static synchronized Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
7、懶漢式-5 – 靜態內部類,執行緒安全
- 靜態內部類是的加載,是呼叫時才會被加載(不會隨著外部類的加載而加載),其實靜態內部類的內部是 餓漢式 的思想,靜態內部類中的常量只會指向一個實體一次(而且該靜態內部類也只能進行一次實體化,不知大家有沒有看懂我說的這里),
- 優點:懶加載、執行緒安全、鎖控制由類的加載機制實作,效率高,
- 缺點:,,,
- 結論:推薦使用,
// 靜態內部類完成, 推薦使用
class Singleton {
private static volatile Singleton instance;
//構造器私有化
private Singleton() {
}
//寫一個靜態內部類,該類中有一個靜態屬性 Singleton
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
//提供一個靜態的公有方法,直接回傳SingletonInstance.INSTANCE
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
8、列舉
- 通過列舉類進行單例控制,不僅能避免多執行緒問題,而且還能防止反序列化重新構建新的物件,
- 優點:懶加載、執行緒安全、防止序列化
- 缺點:,,,
- 結論:推薦使用,
//使用列舉,可以實作單例, 推薦
enum Singleton {
INSTANCE; //屬性
public void lbwNb() {
System.out.println("lbwNb);
}
}
四、測驗
上面我就說這個執行緒安全、哪個執行緒不安全,這不免有老哥會不服,別急,看的測驗代碼一出,看能不能堵住各位老哥的嘴,
public void test(){
//執行緒數
int tCount = 10;
ConcurrentHashMap<String, Object> cMap = new ConcurrentHashMap();
CountDownLatch countDownLatch = new CountDownLatch(tCount);
for (int i = 0; i < tCount; i++) {
Thread t = new Thread(() -> {
Singleton instance = Singleton.getInstance();
System.out.println(instance.hashCode());
cMap.put(String.valueOf(instance.hashCode()), "CHM值不能為空");
countDownLatch.countDown();
});
t.start();
}
countDownLatch.await();
System.out.println(
cMap.size() == 1 ?
"執行緒安全-----(*^_^*)" : "執行緒不安全-----/(ㄒoㄒ)/~~");
}
五、來個小總結
這么多種方法,我該使用那種?隨便?別吧,那需要搞出這么種實作方式干嘛,所以說還是需要斟酌的,大伙說是吧!起碼說哪些可用哪些不可以用吧!!
總的來說執行緒不安全是不能使用的,執行緒安全都是可用的,在綜合實作方式對系統資源的消耗來選擇最佳的方式,
- 不可用:
- 懶漢式-1 – 執行緒不安全
- 懶漢式-3 – 同步代碼塊,執行緒不安全
- 可用:
- 餓漢式-1 – 靜態常量
- 餓漢式-2 – 靜態代碼塊
- 懶漢式-2 --同步方法,執行緒安全
- 懶漢式-4 --雙重檢查,執行緒安全
- 懶漢式-5 – 靜態內部類,執行緒安全
- 列舉
- 推薦使用:
- 懶漢式-4 --雙重檢查,執行緒安全
- 懶漢式-5 – 靜態內部類,執行緒安全
- 列舉
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/226635.html
標籤:其他
