https://www.cnblogs.com/zhili/archive/2012/07/21/ThreadsSynchronous.html 線程同步html
1.c# 的原子操做 能夠防止併發。Interlocked數據庫
(以保證這段代碼的原子性(atomic)操做,即:要麼不執行這段代碼,要麼將這段代碼所有執行完畢。防止併發污染數據)c#
2.線程的優先級安全
static void Main(string[] args) { Thread threadA = new Thread(ThreadMethod); //執行的必須是無返回值的方法 threadA.Name = "A"; Thread threadB = new Thread(ThreadMethod); //執行的必須是無返回值的方法 threadB.Name = "B"; threadA.Priority = ThreadPriority.Highest; threadB.Priority = ThreadPriority.BelowNormal; threadB.Start(); threadA.Start(); Thread.CurrentThread.Name = "C"; ThreadMethod(new object()); Console.ReadKey(); } public static void ThreadMethod(object parameter) { for (int i = 0; i < 500; i++) { Console.Write(Thread.CurrentThread.Name); } }
Thread.CurrentThread.Name = "C"; 當前線程多線程
3. 線程同步併發
什麼是線程安全:性能
線程安全是指在當一個線程訪問該類的某個數據時,進行保護,其餘線程不能進行訪問直到該線程讀取完,其餘線程纔可以使用。不會出現數據不一致或者數據污染。this
線程有可能和其餘線程共享一些資源,好比,內存,文件,數據庫等。當多個線程同時讀寫同一份共享資源的時候,可能會引發衝突。這時候,咱們須要引入線程「同步」機制,即各位線程之間要有個先來後到,不能一窩蜂擠上去搶做一團。線程同步的真實意思和字面意思剛好相反。線程同步的真實意思,實際上是「排隊」:幾個線程之間要排隊,一個一個對共享資源進行操做,而不是同時進行操做。atom
解決線程同步的方法:spa
3.0 鎖
static void Main(string[] args) { Program pro1 = new Program(); Program pro2 = new Program(); Thread threadA = new Thread(pro1.ThreadMethod); //執行的必須是無返回值的方法 threadA.Name = "王文建"; Thread threadB = new Thread(pro2.ThreadMethod); //執行的必須是無返回值的方法 threadB.Name = "生旭鵬"; threadA.Start(); threadB.Start(); Console.ReadKey(); } public void ThreadMethod(object parameter) { lock (this) { for (int i = 0; i < 10; i++) { Console.WriteLine("我是:{0},我循環{1}次", Thread.CurrentThread.Name, i); Thread.Sleep(300); } } }
lock(this) 鎖定 當前實例對象,若是有多個類實例的話,lock鎖定的只是當前類實例,對其它類實例無影響。全部不推薦使用。
lock(typeof(Model))鎖定的是model類的全部實例。 這裏的Model是指某個類名。
lock(obj)鎖定的對象是全局的私有化靜態變量。外部沒法對該變量進行訪問。
lock 確保當一個線程位於代碼的臨界區時,另外一個線程不進入臨界區。若是其餘線程試圖進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。
因此,lock的結果好很差,仍是關鍵看鎖的誰,若是外邊能對這個誰進行修改,lock就失去了做用。
因此,通常狀況下,使用私有的、靜態的而且是隻讀的對象。
總結:
一、lock的是必須是引用類型的對象,string類型除外。
二、lock推薦的作法是使用靜態的、只讀的、私有的對象。
三、保證lock的對象在外部沒法修改纔有意義,若是lock的對象在外部改變了,對其餘線程就會暢通無阻,失去了lock的意義。
不能鎖定字符串,鎖定字符串尤爲危險,由於字符串被公共語言運行庫 (CLR)「暫留」。 這意味着整個程序中任何給定字符串都只有一個實例,就是這同一個對象表示了全部運行的應用程序域的全部線程中的該文本。所以,只要在應用程序進程中的任何位置處具備相同內容的字符串上放置了鎖,就將鎖定應用程序中該字符串的全部實例。一般,最好避免鎖定 public 類型或鎖定不受應用程序lock塊內控制的對象實例。例如,若是該實例能夠被公開訪問,則 lock(this) 可能會有問題,由於不受控制的代碼也可能會鎖定該對象。這可能致使死鎖,即兩個或更多個線程等待釋放同一對象。出於一樣的緣由,鎖定公共數據類型(相比於對象)也可能致使問題。並且lock(this)只對當前對象有效,若是多個對象之間就達不到同步的效果。lock(typeof(Class))與鎖定字符串同樣,鎖定的對象的做用域的範圍太廣了。
3.1 使用Monitor類實現線程同步
Lock關鍵字是Monitor的一種替換用法,lock在IL代碼中會被翻譯成Monitor.
lock(obj)
{
//代碼段
}
就等同於
Monitor.Enter(obj);
//代碼段
Monitor.Exit(obj);
Monitor的經常使用屬性和方法:
Enter(Object) 在指定對象上獲取排他鎖。
Exit(Object) 釋放指定對象上的排他鎖。
Pulse 通知等待隊列中的線程鎖定對象狀態的更改。
PulseAll 通知全部的等待線程對象狀態的更改。
TryEnter(Object) 試圖獲取指定對象的排他鎖。
TryEnter(Object, Boolean) 嘗試獲取指定對象上的排他鎖,並自動設置一個值,指示是否獲得了該鎖。
Wait(Object) 釋放對象上的鎖並阻止當前線程,直到它從新獲取該鎖。
經常使用的方法有兩個,Monitor.Enter(object)方法是獲取鎖,Monitor.Exit(object)方法是釋放鎖,這就是Monitor最經常使用的兩個方法,在使用過程當中爲了不獲取鎖以後由於異常,致鎖沒法釋放,因此須要在try{} catch(){}以後的finally{}結構體中釋放鎖(Monitor.Exit())。
Enter(Object)的用法很簡單,看代碼
static void Main(string[] args) { Thread threadA = new Thread(ThreadMethod); //執行的必須是無返回值的方法 threadA.Name = "A"; Thread threadB = new Thread(ThreadMethod); //執行的必須是無返回值的方法 threadB.Name = "B"; threadA.Start(); threadB.Start(); Thread.CurrentThread.Name = "C"; ThreadMethod(); Console.ReadKey(); } static object obj = new object(); public static void ThreadMethod() { Monitor.Enter(obj); //Monitor.Enter(obj) 鎖定對象 try { for (int i = 0; i < 500; i++) { Console.Write(Thread.CurrentThread.Name); } } catch(Exception ex){ } finally { Monitor.Exit(obj); //釋放對象 } }
3.2 mutex 互斥鎖
四、線程池
上面介紹了介紹了平時用到的大多數的多線程的例子,但在實際開發中使用的線程每每是大量的和更爲複雜的,這時,每次都建立線程、啓動線程。從性能上來說,這樣作並不理想(由於每使用一個線程就要建立一個,須要佔用系統開銷);從操做上來說,每次都要啓動,比較麻煩。爲此引入的線程池的概念。
好處:
1.減小在建立和銷燬線程上所花的時間以及系統資源的開銷
2.如不使用線程池,有可能形成系統建立大量線程而致使消耗完系統內存以及」過分切換」。
在什麼狀況下使用線程池?
1.單個任務處理的時間比較短
2.須要處理的任務的數量大
線程池最多管理線程數量=「處理器數 * 250」。也就是說,若是您的機器爲2個2核CPU,那麼CLR線程池的容量默認上限即是1000
經過線程池建立的線程默認爲後臺線程,優先級默認爲Normal。