基礎知識重要嗎?真的很重要。
就在筆者與同事聊天中突然同事提出一個問題,讓筆都有點亂了手腳(有點誇張),題目是這樣的:
問:Hashtable 是線程安全的嗎?
答:…… (沉默中,Yes Or No?Why?)
帶着問題我們一步一步的解答:
1、線程安全
概念: 通俗的講就是多線程訪問時,采用了加鎖機制,當一個線程操作臨界區時,對臨界區進行保護,其他線程等前面線程操作完才能排隊操作臨界區。這樣保障數據一致減少數據污染。
2、求證
各種資料顯示 Hashtable 的 Synchronized 靜態方法提供線程安全。那根據資料信息我們找到源代碼,找到 Synchronized 是如何提供線程安全的。
都知道 Hashtable 來自 System.Collections 那我們就從他着手找到 Hashtable 中的靜態方法 Synchronized:



從源碼中可以看出,Synchronized 返回一個 SyncHashtable 實例。我們接着找 SyncHashtable
SyncHashtable 繼承自 Hashtable,之所以實現線程安全操作,因為 SyncHashtable 中就已經增加 lock 、


3、結論
到這里至少能證明 Hashtable 在實現靜 Synchroinzed 方法時是線程安全的沒錯吧!
下面寫個實例來說明如何使用 Synchronized 實現並發情況下,既有讀線程,又有寫線程的線程安全實例:

1 private Hashtable _ht = Hashtable.Synchronized(new Hashtable()); 2 static void Main(string[] args) 3 { 4 new Program().TestLock(); 5 Console.WriteLine($"主線程:{Thread.CurrentThread.ManagedThreadId}"); 6 Console.ReadKey(); 7 } 8 9 public void TestLock() 10 { 11 Task.Factory.StartNew(obj => SyncMethodA((string)obj), "laowang"); 12 Task.Factory.StartNew(obj => SyncMethodB((string)obj), "liupangzi"); 13 Thread.Sleep(6000); 14 Console.WriteLine($"輸出值:{ _ht[0]}"); 15 } 16 17 18 private void SyncMethodA(string param) 19 { 20 Console.WriteLine($"方法A線程:{Thread.CurrentThread.ManagedThreadId}"); 21 lock (_ht.SyncRoot) 22 { 23 Thread.Sleep(5000); 24 _ht[0] = "SyncMethodA"; 25 Console.WriteLine($"A方法輸出值:{ _ht[0]}"); 26 } 27 } 28 29 private void SyncMethodB(string param) 30 { 31 Console.WriteLine($"方法B線程:{Thread.CurrentThread.ManagedThreadId}"); 32 Console.WriteLine($"B方法輸出值:{ _ht[0]}"); 33 _ht[0] = "SyncMethodB"; 34 }
為了看到效果,線程A使用了鎖,並睡眠 5 秒,后設置 hashtable 值為 SyncMethodA ,線程B先讀取 hashtable 中的值,再寫入 SyncMethodB 值到 hashtable 中。在寫入值這句上會被 hashtable 自動銷鎖住 ,直到A釋放掉 SyncRoot 為止。
上面代碼中我們實現鎖 SyncRoot 方式進行測試,結果:


如果我們更改鎖的對象為 hashtable 實例本身,lock(_ht) ,那么線程B不會在 hashtable="SyncMethodB" 這句話自動鎖住。所以輸出值是:SyncMethodA
注:以上代碼請忽略方法傳值