今天重構公司的代碼,看到有一個單例的對象,在整個系統中到處都存在調用它的身影,因為我們這個項目會在應用伺服器(server)第一次啟動的時候加載資料庫中的代碼表(為什麼要先加載,因為這個項目采用的是C/S模式,利用remoting進行通信,在用戶端啟動的時候會多次擷取代碼表中的不同資料。)
1 public class CodeTableSingleTon
2 {
3 ///防止外部被執行個體化
4 private CodeTableSingleTon(){
5 //進行資料的讀取操作
6 }
7 //鎖
8 private static readonly object _lock=new object();
9
10 private static CodeTableSingleTon _instance;
11
12 public static CodeTableSingleTon Instance
13 {
14 get
15 {
16 if(_instance==null)
17 {
18 lock(_lock){
19 if(_instance==null)
20 {
21 _instance=new CodeTableSingleTon();
22 }
23 }
24 }
25 return _instance;
26 }
27 }
28
29
30 }
上面代碼就是項目的實作方式,我了解過單例模式,單例模式是控制對象的建立,可以實作延遲加載,隻有在對象被調用的時候才會真正的執行對象的執行個體化,可以在一定程度上減少記憶體的耗用(是在不使用該對象的情況下)。既然在整個系統中隻有一個該對象, 因為項目是采用多線程處理用戶端的請求,是以每個線程都可以擷取到該對象進行資料的擷取,系統運作也沒發現 由于這個對象的建立或者其他問題。
但是我深入的想了一下,如果我在單例對象中加入一個計數器,表示單例對象被調用的次數,那麼這個對象内部的屬性 可能會同時被多個線程進行更新。
1 public class SingleTon
2 {
3
4 private static SingleTon _instance;
5 private static readonly object _lock=new object();
6 private SingleTon(){} //私有的構造函數 確定該執行個體不能在外部直接通過new執行個體化
7 public static long totalNum=0;//初始化計數器預設值為0
8 public static SingleTon Instance
9 {
10 get
11 {
12 if(_instance==null)
13 {
14 lock(_lock)
15 {
16 if(_instance==null)
17 {
18 _instance=new SingleTon();
19 }
20 }
21 }
22 totalNum=totalNum+1; //每次調用計數器都會加1
//Consle.WriteLine(totalNum);
23 return _instance;
24 }
25 }
26 }
我嘗試開啟了多個線程來執行這段代碼,沒有發現totalNum的值存在由于多個線程的調用出現重複資料輸出的情況。那麼我心裡一直在糾結一個事,就是說假如兩個線程都在同一時間擷取到了這個單例對象,那麼都會依次執行計數器加1,如果說兩個線程執行到totalNum=totalNum+1 這句話的時候不是在同時的,那麼不會出現問題。
如果這兩個線程中了彩票了,同時執行了totalNum=totalNum+1,那麼就會導緻計數器少算了一次調用嗎?我在測試,開啟了100個線程,沒有發現重複的值存在,難道我的了解是錯誤的嗎?我記得在多線程下操作同一資料是會出現這個問題的?不知道這個對單例模式是否适用呢?糾結糾結,求準确的回複
如果單例的方式存在問題,那麼采用靜态字段也會出現這個問題,就無法統計計數器了。mygod 腦袋要炸了
有人的地方就有政治,有政治就有鬥争,但我讨厭政治,讨厭無休止的迎合。