一. 鎖機制的背景介紹html
本章節,將結合多線程來介紹鎖機制, 那麼問題來了,什麼是鎖呢? 爲何須要鎖? 爲何要結合多線程來介紹鎖呢?鎖的使用場景又是什麼呢? DotNet中又有哪些鎖呢?多線程
在接下來的幾個章節中,將陸續解答這些問題。併發
PS:spa
多個線程對一個共享資源進行使用的時候,會出問題, 好比實際的業務場景,入庫和出庫操做同時進行,庫存量就會存在併發問題。因此鎖就是用來解決多線程資源競用的問題。線程
Net領域中,鎖機制很是多,好比:時間鎖、信號量、互斥鎖、讀寫鎖、互鎖、異變結構,主要咱們能夠把他們劃分爲三大類:3d
①.用戶模式鎖:就是經過一些cpu指令或者一個死循環,來達到達到線程的等待和休眠。
②.內核模式鎖:就是調用win32底層的代碼,來實現thread的各類操做。
③.混合鎖:用戶模式+內核模式code
其中用戶模式鎖又分爲這麼幾類:異變結構、互鎖和旋轉鎖。htm
二. 異變結構blog
背景:一個線程讀,一個線程寫,在release模式下會出現bug,致使主線程沒法執行,緣由在前面章節已經介紹過了。資源
方式一:利用MemoryBarrier方法進行處理 。(前面章節已介紹)
方式二:利用VolatileRead/Write方法進行處理。 (前面章節已介紹)
方式三:volatile關鍵字進行處理,個人read和write都是從memrory中讀取,讀取的都是最新的。(下面的案例使用volatile關鍵字後,主線程能夠執行)
代碼實踐:
1 public static volatile bool isStop = false;
2 //使用Volatile關鍵字處理 3 var t = new Thread(() => 4 { 5 var isSuccess = false; 6 while (!isStop) 7 { 8 isSuccess = !isSuccess; 9 } 10 }); 11 t.Start(); 12 Thread.Sleep(1000); 13 isStop = true; 14 t.Join(); 15 Console.WriteLine("主線程執行結束!"); 16 Console.ReadLine();
代碼結論:使用volatile關鍵字進行修飾,解決共享資源的競用問題。
三. 互鎖
互鎖結構(Interlocked類),經常使用的方法有:
* Increment:自增操做
* Decrement:自減操做
* Add: 增長指定的值
* Exchange: 賦值
* CompareExchange: 比較賦值
代碼實踐:
1 { 2 //1. 自增 3 { 4 int a = 1; 5 Interlocked.Increment(ref a); 6 Console.WriteLine("自增後的數據爲:{0}", a); 7 } 8 //2. 自減 9 { 10 int b = 2; 11 Interlocked.Decrement(ref b); 12 Console.WriteLine("自減後的數據爲:{0}", b); 13 } 14 //3. 增長操做 15 { 16 int c = 3; 17 Interlocked.Add(ref c, 4); 18 Console.WriteLine("增長後的數據爲:{0}", c); 19 20 } 21 //4. 賦值操做 22 { 23 int d = 4; 24 Interlocked.Exchange(ref d, 55); 25 Console.WriteLine("賦值後的數據爲:{0}", d); 26 27 } 28 //5. 比較賦值 29 { 30 //Interlocked.CompareExchange(ref num1, sum, num2); // num1==num2 ; num1=sum; 31 int ee = 5; 32 Interlocked.CompareExchange(ref ee, 15, 5); 33 Console.WriteLine("比較賦值後的數據爲:{0}", ee); 34 35 Interlocked.CompareExchange(ref ee, 100, 15); 36 Console.WriteLine("比較賦值後的數據爲:{0}", ee); 37 38 } 39 40 }
代碼結果:
四. 旋轉鎖
旋轉鎖(SpinLock), 特殊的業務邏輯讓thread在用戶模式下進行自選,欺騙cpu當前thread正在運行中。
SpinLock類有兩個核心方法,分別是:Enter和Exit方法。
代碼實踐:
1 { 2 //下面代碼的結果:num從0-249,且是有序的。 3 //若是把旋轉鎖去掉,num將沒有任何順序 4 for (int i = 0; i < 5; i++) 5 { 6 Task.Factory.StartNew(() => 7 { 8 for (int j = 0; j < 50; j++) 9 { 10 try 11 { 12 var b = false; 13 sl.Enter(ref b); 14 Console.WriteLine(num++); 15 } 16 catch (Exception ex) 17 { 18 Console.WriteLine(ex.Message); 19 } 20 finally 21 { 22 sl.Exit(); 23 } 24 } 25 }); 26 } 27 }
代碼結果:下面代碼的結果:num從0-249,且是有序的;若是將旋轉鎖的代碼去掉,num的輸出將沒有任何順序可言。