C#多線程基礎(chǔ)知識匯總
最近自己寫了個小爬蟲,里面用到了多線程技術(shù),忽然發(fā)現(xiàn)對此技術(shù)竟然有些陌生了,于是乎開始瘋狂的去問度娘,在此記錄下來,以便自己和各位小伙伴們學(xué)習(xí)。
一、什么是線程
一個應(yīng)用程序就相當(dāng)于一個進(jìn)程,進(jìn)程擁有應(yīng)用程序的所有資源進(jìn)程包括線程,進(jìn)程的資源被線程共享,但不擁有線程。我們可以打開電腦中的任務(wù)管理器,運行的.exe都是一個進(jìn)程,里面的分支是線程。
二、多線程
多線程其實就是進(jìn)程中一段并行運行的代碼
1. 創(chuàng)建并啟動線程
static void Main() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; var thread = new Thread(Test1); thread.Start(); Console.WriteLine(threadId + "_Main()"); Console.Read(); } /// <summary> /// 測試方法 /// </summary> private static void Test1() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine(threadId + "_Test()"); for (int i = 0; i < 10; i++) { Console.WriteLine(threadId + "_" + i); } }
結(jié)果:
2、暫定線程諾干時間
static void Main() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; var thread = new Thread(Test1); thread.Start(); Console.WriteLine($"主線程Id{threadId}_Main()"); Console.Read(); } /// <summary> /// 測試方法 /// </summary> private static void Test1() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"輔線程Id{threadId}_Test()"); for (int i = 0; i < 10; i++) { Thread.Sleep(1000);//單位毫秒 Console.WriteLine($"輔線程Id{threadId}_{DateTime.Now}"); } }
結(jié)果:
3、線程合并
Thread.Join操作會阻塞當(dāng)前線程,等待子線程完成后再進(jìn)行運行。
static void Main() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; var thread = new Thread(Test1); thread.Start(); Console.WriteLine($"主線程Id{threadId}_Main()1"); thread.Join(); Console.WriteLine($"主線程Id{threadId}_Main()2"); Console.Read(); } /// <summary> /// 測試方法 /// </summary> private static void Test1() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"輔線程Id{threadId}_Test()"); for (int i = 0; i < 10; i++) { Thread.Sleep(1000);//單位毫秒 Console.WriteLine($"輔線程Id{threadId}_{DateTime.Now}"); } }
結(jié)果:
4、線程終止
static void Main() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; var thread = new Thread(Test1); thread.Start(); Console.WriteLine($"主線程Id{threadId}_Main()1"); Thread.Sleep(3000); thread.Abort(); Console.WriteLine($"主線程Id{threadId}_Main()2"); Console.Read(); } /// <summary> /// 測試方法 /// </summary> private static void Test1() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"輔線程Id{threadId}_Test()"); for (int i = 0; i < 10; i++) { Thread.Sleep(1000);//單位毫秒 Console.WriteLine($"輔線程Id{threadId}_{DateTime.Now}"); } }
結(jié)果:
5、線程中的參數(shù)傳遞
static void Main() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"主線程Id{threadId}_Main()"); //第一種參數(shù)傳遞方式 var thread1 = new Thread(() => Test1("小魔王")); thread1.Start(); //第二種參數(shù)傳遞方式(參數(shù)只能是一個,object類型) var parameterizedThreadStart = new ParameterizedThreadStart(Test2); var thread2 = new Thread(parameterizedThreadStart); thread2.Start("大魔王"); Console.Read(); } /// <summary> /// 測試方法 /// </summary> private static void Test1(string name) { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"輔線程Id{threadId}_我的名字叫:{name}"); } /// <summary> /// 測試方法 /// </summary> private static void Test2(object name) { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"輔線程Id{threadId}_我的名字叫:{name}"); }
結(jié)果:
還有其他的傳遞方式,在此先不做說明了,這里只介紹Thread提供的這么幾種。
6、線程安全和線程鎖Lock
線程安全就是多線程訪問時,采用了加鎖機制,當(dāng)一個線程訪問該類的某個數(shù)據(jù)時,進(jìn)行保護(hù),其他線程不能進(jìn)行訪問直到該線程讀取完,其他線程才可使用。線程安全情況下,不會出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染的問題。 線程不安全就是不提供數(shù)據(jù)訪問保護(hù),有可能出現(xiàn)多個線程先后更改數(shù)據(jù)造成所得到的數(shù)據(jù)是臟數(shù)據(jù)! 若每個線程中對全局變量、靜態(tài)變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執(zhí)行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。
lock 關(guān)鍵字通過獲取指定對象的互斥鎖,將語句塊標(biāo)記為臨界區(qū),執(zhí)行語句然后釋放該鎖。
lock 確保當(dāng)一個線程位于代碼的臨界區(qū)時,另一個線程不進(jìn)入臨界區(qū)。如果其他線程試圖進(jìn)入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。使用Lock,會導(dǎo)致整個應(yīng)用程序串行化,降低程序的并發(fā)能力,影響性能。
到底什么場景下要使用lock保證線程安全:該串行就串行,該并行就并行。
加鎖前:
public static int i = 1000000; static void Main() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; for (int j = 0; j < 2; j++) { var thread = new Thread(Test1); thread.Start(); } Console.Read(); } /// <summary> /// 測試方法 /// </summary> private static void Test1() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; Console.WriteLine($"輔線程Id{threadId}_i初始值:{i}"); int count = 0; for (int j = 0; j < 1000000; j++) { i--; count++; } Console.WriteLine($"輔線程Id{threadId}_運行次數(shù):{count}"); Console.WriteLine($"輔線程Id{threadId}_i結(jié)束值:{i}"); }
結(jié)果:
加鎖后:
public static int i = 1000000; private readonly static object objLock = new object(); static void Main() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; for (int j = 0; j < 2; j++) { var thread = new Thread(Test1); thread.Start(); } Console.Read(); } private static void Test1() { //獲取線程Id var threadId = Thread.CurrentThread.ManagedThreadId; int count = 0; lock (objLock) { Console.WriteLine($"輔線程Id{threadId}_i初始值:{i}"); for (int j = 0; j < 1000000; j++) { i--; count++; } } Console.WriteLine($"輔線程Id{threadId}_運行次數(shù):{count}"); Console.WriteLine($"輔線程Id{threadId}_i結(jié)束值:{i}"); }
結(jié)果:
好啦,今天關(guān)于線程的知識就分箱到這里啦。
到此這篇關(guān)于C#多線程基礎(chǔ)知識匯總的文章就介紹到這了,更多相關(guān)C#多線程基礎(chǔ)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#/VB.NET讀取條碼類型及條碼在圖片中的坐標(biāo)位置實例
我們在創(chuàng)建條形碼時,如果以圖片的方式將創(chuàng)建好的條碼保存到指定文件夾路徑,可以在程序中直接加載圖片使用;已生成的條碼圖片,需要通過讀取圖片中的條碼信息,如條碼類型、條碼繪制區(qū)域在圖片中的四個頂點坐標(biāo)位置等,可參考本文中的方法2023-10-10WPF利用RichTextBox實現(xiàn)富文本編輯器
在實際應(yīng)用中,富文本隨處可見,那么在WPF開發(fā)中,如何實現(xiàn)富文本編輯呢?本文以一個簡單的小例子,簡述如何通過RichTextBox實現(xiàn)富文本編輯功能,需要的可以參考下2024-02-02基于C#實現(xiàn)Windows服務(wù)的方法詳解
在實際應(yīng)用過程中,有時候我們希望開發(fā)的程序,不需要界面,直接開機就可以長時間運行,這時候,我們可以考慮做成一個Windows服務(wù)。這篇文章跟大家介紹一下,如何基于C#實現(xiàn)Windows服務(wù)的創(chuàng)建、安裝、啟動、停止和卸載,需要的可以參考一下2022-09-09