C#多線程基礎(chǔ)知識匯總
最近自己寫了個小爬蟲,里面用到了多線程技術(shù),忽然發(fā)現(xiàn)對此技術(shù)竟然有些陌生了,于是乎開始瘋狂的去問度娘,在此記錄下來,以便自己和各位小伙伴們學(xué)習(xí)。
一、什么是線程
一個應(yīng)用程序就相當(dāng)于一個進程,進程擁有應(yīng)用程序的所有資源進程包括線程,進程的資源被線程共享,但不擁有線程。我們可以打開電腦中的任務(wù)管理器,運行的.exe都是一個進程,里面的分支是線程。
二、多線程
多線程其實就是進程中一段并行運行的代碼
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)前線程,等待子線程完成后再進行運行。
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ù)時,進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程才可使用。線程安全情況下,不會出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染的問題。 線程不安全就是不提供數(shù)據(jù)訪問保護,有可能出現(xiàn)多個線程先后更改數(shù)據(jù)造成所得到的數(shù)據(jù)是臟數(shù)據(jù)! 若每個線程中對全局變量、靜態(tài)變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執(zhí)行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。
lock 關(guān)鍵字通過獲取指定對象的互斥鎖,將語句塊標(biāo)記為臨界區(qū),執(zhí)行語句然后釋放該鎖。
lock 確保當(dāng)一個線程位于代碼的臨界區(qū)時,另一個線程不進入臨界區(qū)。如果其他線程試圖進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。使用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-10
WPF利用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

