非線程安全
引發線程安全的原因是,多個線程可以同時操作全局變量/共享變量/靜態變量/磁盤文件/數據庫的值就可能存在線程安全問題,因為多個線程操作,出現了覆蓋。List集合也是非線程安全的。
線程安全
多線程同時運行,如果每次運行的結果和單線程運行的結果一致,那么就是線程安全的。
Lock鎖
概念
解決多線程沖突問題,Lock是語法糖,Monitor.Enter,占據一個引用,別的線程就只能等着。鎖的本質就是把多線程在某些特定場合下變成單線程,來完成某些特定操作。
在日常工作中,有些是特定需要鎖的,更多的時候我們可以把數據拆分,避免多線程操作同一個數據,這樣既安全又高效。例如有10000個任務,那可以進行拆分,某個線程執行1-100給任務。
Lock鎖不允許的類型
String:string在內存分配上是重用的,會沖突。這么話應該這么理解,比如你定義一個變量name=”張三”,再定義一個變量temeName=”張三”,那么在C#內存分配時會指向同一個引用。
Null:可以運行,不能編譯通過。
詳解Lock
Lock鎖的兩鍾方式:
Lock(this)不推薦的鎖如果只是當前內部實例使用,則不會沖突。外面如果也要用實例,就沖突了。
public void DoTest() { //遞歸調用 lock(this)不會死鎖,原因:這里是同一個線程,這個引用就是被這個線程鎖占據 //鎖的本質是讓這個引用不會被其他線程所占據 lock (this) { Thread.Sleep(500); iDotestNum++; if (DateTime.Now.Day < 13&&iDotestNum<10) { Console.WriteLine($"這是第{DateTime.Now.Day}天,第{iDotestNum}次"); this.DoTest(); } else { Console.WriteLine("結束啦"); } } } private int iDotestNum = 0;
外部也要使用實例:
Test test = new Test(); Task.Delay(1000).ContinueWith(t => { lock (test)//此處是鎖住test實例 { Console.WriteLine("*********Start**********"); Thread.Sleep(5000); Console.WriteLine("*********End**********"); } }); //會沖突,因為DoTest方法里的lock(this)就是鎖住當前的實例即:test test.DoTest(); public class Test{ public void DoTest() { //遞歸調用 lock(this)不會死鎖,原因:這里是同一個線程,這個引用就是被這個線程鎖占據 //鎖的本質是讓這個引用不會被其他線程所占據 lock (this) { Thread.Sleep(500); iDotestNum++; if (DateTime.Now.Day < 13&&iDotestNum<10) { Console.WriteLine($"這是第{DateTime.Now.Day}天,第{iDotestNum}次"); this.DoTest(); } else { Console.WriteLine("結束啦"); } } } private int iDotestNum = 0; }
標准鎖,微軟推薦的標准鎖
private static readonly object Form_Lock = new object();
lock(Form_Lock);
#region 標准鎖 for (int i = 0; i < 1000; i++) { Task.Run(() => { lock (Form_Lock)// 任意時刻只有一個線程能進入方法塊兒 { intAsyncNum++; } }); } Console.WriteLine($"intAsyncNum={intAsyncNum}"); #endregion