關於多線程學習總結(四) 鎖


寫在前面

在進入鎖的學習前來看看Thread的方法,之前一直對這個方法不了解,今天學習了下。在學習之前看兩段代碼吧:

 1 static void Main(string[] args)
 2 {
 3             Thread thread = new Thread(new ThreadStart(myThread1));
 4             thread.Start();
 5             thread.Join();  //關鍵這一行  6             Console.WriteLine("主線程");
 7             Console.ReadKey();
 8  }
 9 public static void myThread1()
10 {
11             Thread.Sleep(1000);
12             Console.WriteLine("1測試線程{0}",++count1);
13 }

先來看看效果再說話(左邊截圖為5行未被注釋,右邊為被注釋):

在這之前,小弟一直不明白為什么加了上面第5行與不加第五行區別是什么,今天終於知道了,原來是線程之間原本並行執行通過使用Join()使其串行化,在這個例子里myThread1()被調用,而此方法存在一個線程阻塞,此時先打印“主線程”(上 右圖);然而調用了Join()方法,使其原本並行化的線程串行化,所以主線程必須等待子線程執行完才能執行,此時先打印“1測試線程1”(上 左圖)。<以上的串行與並行用詞有點不嚴謹,主要事為了方便理解而已>

進入鎖的學習

此句網上COPY來的:我們拋開.NET環境看線程同步,無非是執行兩種操作:一是互斥/加鎖,目的是保證臨界區代碼操作的“原子性”;另一種是信號燈操作,目的是保證多個線程按照一定順序執行,如生產者線程要先於消費者線程執行。

暫時先腦海中留點鎖的印象就好啦!下面介紹兩個類:

Monitor類

通過查MSDN我們可以發現Monitor類一共有17個方法,但是這17個方法並不是都常用,下面我簡單列舉幾個介紹並結合實例理解理解:

一、Enter()與Exit()

  在我看來它目前最主要的功能是設置邊界,使原本並行執行的線程順序化,此句小弟斷章取義,不對請指正

 1         static void Main(string[] args)
 2         {
 3             for (int i = 0; i < 15; i++)
 4             {
 5                 Thread thread = new Thread(new ThreadStart(myThread1));
 6                 thread.Start();
 7             }
 8             Console.WriteLine("主線程");
 9             Console.ReadKey();
10         }
11         static object ob = new object();
12         static int count1 = 0;
13         public static void myThread1()
14         {
15             Monitor.Enter(ob);  //作用域開始 16             Thread.Sleep(10);
17             Console.WriteLine("1測試線程{0}", ++count1);
18             Monitor.Exit(ob);  //作用域結束 19         }

看看效果再說話(左邊截圖為使用Enter()和Exit(),右邊木有用):

看到區別木有,話說程序員都是聰明的班子,哈哈哈、、、、

二、Wait()與Pulse()

我們先來看看MSDN的官方介紹

Wait()——釋放對象上的鎖並阻止當前線程,直到它重新獲取該鎖

Pulse()——通知等待隊列中的線程鎖定對象狀態的更改

簡而言之,Wait()方法就是暫時釋放資源鎖,線程進入等待隊列,此時其它線程獲取資源鎖;Pulse()方法則是喚醒等待隊列中的線程,重新得到資源鎖。

 1         static void Main(string[] args)
 2         {
 3             for (int i = 0; i < 5; i++)
 4             {
 5                 Thread thread = new Thread(new ThreadStart(myThread1));
 6                 thread.Start();
 7                 Thread thread1 = new Thread(new ThreadStart(myThread2));
 8                 thread1.Start();
 9             }
10             Console.WriteLine("主線程");
11         }
12         static object ob = new object();  
13         static int count1 = 0;
14         static int count2 = 0;
15         public static void myThread1()
16         {
17             Monitor.Enter(ob);
18             Thread.Sleep(10);
19             Console.WriteLine("1測試線程{0}", ++count1);
20             Monitor.Wait(ob);
21             Console.WriteLine("wait");
22             Monitor.Pulse(ob);
23             Monitor.Exit(ob);
24         }
25         public static void myThread2()
26         {
27             Monitor.Enter(ob);
28             Thread.Sleep(10);
29             Console.WriteLine("2測試線程{0}", ++count2);
30             Monitor.Wait(ob);
31             Console.WriteLine("wait2");
32             Monitor.Pulse(ob);
33             Monitor.Exit(ob);
34         }

運行結果如下圖:

上面打印交替次數是沒有規律的,每次都會有偏差

再總結幾點:

1.Monitor.Pulse()調用后線程還是會執行下一行代碼,不會執行另一個線程,除非再調用Monitor.Wait()讓線程進入等待狀態

2.只有鎖的當前所有者可以使用 Pulse 向等待對象發出信號

3.當前擁有指定對象上的鎖的線程調用此方法以便向隊列中的下一個線程發出鎖的信號。 接收到脈沖后,等待線程就被移動到就緒隊列中。 在調用 Pulse 的線程釋放鎖后,就緒隊列中的下一個線程(不一定是接收到脈沖的線程)將獲得該鎖(此句來自MSDN)

ReaderWriterLock

說句實話,這個類我還真不太熟悉,簡單介紹我知道的吧!

我們都知道我們日常代碼中,絕大部分都是讀取,少部分為寫入,而我們前面學習的Monitor類在這里就有些不適合了,因此就出現了ReaderWriterLock這個類,它的好處就是起到,並實現了”寫入串行“,”讀取並行“的神奇效果。

不過這個類還不慎了解,此處留個坑,待填、、、

關於實習

今天又是一個安逸的一天,木有工作,唯一安排的就是簽訂了入職協議,余下的時間自由自配,於是自己學習吧!傳說我們公司女程序員還不算少,15個人中我就看見了六七個,曾經想象中的女屌絲請男屌絲找Bug終於看見了,木有想象中的壯觀。明天開始培訓了,好好學吧,學海無涯,回頭也木有岸,成長ing

------如果你覺得此文對你有所幫助,別忘了點擊下右下角的推薦咯,謝謝!------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM