多執行緒中的單例模式

2021-10-08 16:16:04 字數 3945 閱讀 7585

第一種寫法:餓漢式

//餓漢式

public

class

singleobject1

public

static singleobject1 getinstance()

}

第二種寫法:懶漢式

1、迭代一:

//懶漢式: 在多執行緒環境下不安全,會產生多個例項!

public

class

singleobject2

public

static singleobject2 getinstance()

return instance;

}public

static

void

main

(string[

] args)).

start()

;});

}}

singleobject2()

...singleobject2()

...com.wzj.執行緒.單例模式.singleobject2@7ea6e10f

singleobject2()

...singleobject2()

...singleobject2()

...com.wzj.執行緒.單例模式.singleobject2@7fdaab5b

com.wzj.執行緒.單例模式.singleobject2@3bbb38b7

com.wzj.執行緒.單例模式.singleobject2@1dc727cc

com.wzj.執行緒.單例模式.singleobject2@7e611cce

分析:是什麼原因導致的呢?因為多執行緒是非同步執行的,在某個時間點多個執行緒可能會同時執行到**中的①處,然後繼續往下執行,可能就會導致該類產生多個例項。既然分析出了原因是因為某個時間點同時進來的多個執行緒導致,那麼我就加鎖讓他們乙個乙個同步進來。

2、迭代二:加鎖

public

static singleobject2 getinstance()

}return instance;

}

singleobject2()

...com.wzj.執行緒.單例模式.singleobject2@7ea6e10f

com.wzj.執行緒.單例模式.singleobject2@7ea6e10f

com.wzj.執行緒.單例模式.singleobject2@7ea6e10f

com.wzj.執行緒.單例模式.singleobject2@7ea6e10f

com.wzj.執行緒.單例模式.singleobject2@7ea6e10f

加完鎖之後,確實變成單例了。但是你有沒有發現每次呼叫該方法執行裡面的**的時候都加鎖,這會使得程式的執行效率降低。

3、迭代三:使用雙重檢查機制

public

static singleobject2 getinstance()

}//②

}return instance;

}

分析:假設兩個執行緒t1,t2執行到了①處,假設t1執行緒先搶到cpu的執行權,然後獲取了鎖,這時t2是進不來的,等t1執行到了②處,假設t2執行緒搶到了cpu的執行權,這時它進去執行if判斷結果是不滿足條件,因為t1執行緒已經建立了該類的物件,然後t2也執行完了,這時其他執行緒進來直接執行③處,由於不為空所以直接返回例項了,要是不加③處的**,就每個執行緒進來都得搶鎖,然後在④處判斷,因為耗時而且沒必要,所以在③處加該判斷是很有必要的!

4、迭代四:volatile

你天真的以為用了雙重檢查機制就完事了,小夥子還是太年輕。

雙重檢查機制可能會出現空指標的問題。這是由於編譯器為了優化可能會幫你做的指令重排序!

private

static

volatile singleobject2 instance;

5、說清楚什麼情況下雙重檢查機制會導致空指標的問題!

我為什麼會問這個呢?因為不是我問的,哈哈哈,因為今天我在寫單例的時候,由於是多執行緒的訪問,我就將它寫成了這種雙重檢查+

volatile的形式,然後提交後,不料就被function leader給看到了,就連環炮來問我,問我這樣寫的好處,我就一一跟它說了,他笑著說沒見過加類鎖這種形式,說我寫的不規範,我:額,**不規範了,還說應該拿instance作為鎖,我說第一次進來instance不是空的嗎,怎麼可以作為鎖呢?這不是導致空指標嗎,他沉默了,然後他要問為什麼要加兩次判斷,這不是多餘嗎,我還是跟他解釋,他又沉默了。然後他又問為什麼要加volatile,我剛開始也不是特別清楚,我就和他說只知道是編譯器為了優化幫我們做了重排序,可能會導致空指標。所以我加上volatile關鍵字禁止重排序,這樣就可以避免這種情況的發生,然後他說這怎麼會空指標啊,就算重排序也沒問題啊,他理解的重排序是編寫**的時候互換位置,然後又說不要在網上看了一下就直接用,突顯你會新技術啊,這可是要投產的,所以你看你加這個volatile根本什麼用都沒有,寫的多餘,耗費效能,我:額,耗費個屁的效能。要說效能這專案中好多**得重構。當然這是我心裡想的,我表明就笑笑不說話,你是大哥,你愛咋樣咋樣!。

public

class

singleobject2

private

singleobject2()

public

static singleobject2 getinstance()

}}return instance;

}public

static

void

main

(string[

] args)).

start()

;});

}}

在①處其實 new singleobject2(),其實不是乙個原子性的操作,它可以分為三步

1、分配記憶體空間

2、初始化物件

3、將物件指向剛分配的記憶體空間

但是有些編譯器為了效能的原因,可能會將第二步和第三步進行重排序,順序就成了:

1、分配記憶體空間

2、將物件指向剛分配的記憶體空間

3、初始化物件

//使用靜態內部類的方式

public

class

singleobject3

private

static

class

instanceholder

public

static singleobject3 getinstance()

}

//使用列舉來實現單例,很好,但是個人感覺不太優雅,可能是我太菜了!

public

class

singleobject4

private

enum singleton

public singleobject4 getinstance()

}public

static singleobject4 getinstance()

public

static

void

main

(string[

] args)}.

start()

);}}

最後:來自雖然帥,但是菜的cx

多執行緒中的單例模式

第一種寫法 餓漢式 public class singleobject1 public static singleobject1 getinstance 第二種寫法 懶漢式 在多執行緒環境下不安全,會產生多個例項 public class singleobject2 public singleobj...

多執行緒 單例模式

單例模式 是非常典型常用的一種設計模式 乙份資源只能被申 載一次 單例模式的方法建立的類在當前程序中只有乙個例項 資源的程式初始化的時候就去載入,後面使用的時候直接使用,使用的時候比較流暢,有可能會載入用不上的資源,導致程式初始化時間比較慢。include class single instance...

單例模式多執行緒

單例模式 確保某個類只有乙個例項化物件 import time class a from threading import lock instance none lock lock def new cls,args,kwargs 加鎖確保時間片不發生輪轉 with cls.lock ifnot cl...