基本概念
線程
- 被定義為程序的執(zhí)行路徑,也叫執(zhí)行單元
- 線程是輕量級(jí)進(jìn)程;使用線程節(jié)省了 CPU 周期的浪費(fèi),同時(shí)提高了應(yīng)用程序的效率
進(jìn)程
- 是Windows系統(tǒng)中的一個(gè)基本概念,它包含著一個(gè)運(yùn)行程序所需要的資源。一個(gè)正在運(yùn)行的應(yīng)用程序在操作系統(tǒng)中被視為一個(gè)進(jìn)程
- 一個(gè)進(jìn)程可以包括一個(gè)或多個(gè)線程, 注:至少得有一個(gè)線程
- 進(jìn)程之間是相對(duì)獨(dú)立的,一個(gè)進(jìn)程無(wú)法訪問(wèn)另一個(gè)進(jìn)程的數(shù)據(jù)
查看當(dāng)前系統(tǒng)中的進(jìn)程
打開(kāi)任務(wù)管理器,查看當(dāng)前運(yùn)行的進(jìn)程
編輯
查看當(dāng)前系統(tǒng)中的線程
在任務(wù)管理器里面查詢當(dāng)前總共運(yùn)行的線程數(shù)
****
編輯****
并行與串行(異步與同步)
- 并行(異步): 多個(gè)線程同時(shí)執(zhí)行任務(wù)
- 舉例:小明在燒開(kāi)水的同時(shí)去洗菜了
- 串行(同步): 一個(gè)任務(wù)執(zhí)行完后才能執(zhí)行下一個(gè)
- 舉例:小明在燒開(kāi)水,等開(kāi)水燒開(kāi)后再去洗菜
線程的生命周期
- 新建 :當(dāng)線程實(shí)例被創(chuàng)建但 Start 方法未被調(diào)用時(shí)的狀況
- 就緒 :當(dāng)線程準(zhǔn)備好運(yùn)行并等待 CPU 調(diào)度
- 不可運(yùn)行 :下面的幾種情況下線程是不可運(yùn)行的:
- 已經(jīng)調(diào)用 Sleep 方法
- 已經(jīng)調(diào)用 Wait 方法
- 通過(guò) I/O 操作阻塞
- 死亡狀態(tài) :當(dāng)線程已完成執(zhí)行或已中止時(shí)的狀況
主線程
- 一個(gè)進(jìn)程可以包含若干個(gè)線程,在進(jìn)程入口執(zhí)行的 第一個(gè)線程被視為這個(gè)進(jìn)程的主線程 。
- 在 C# 中,都是以Main()方法作為入口的,當(dāng)調(diào)用此方法時(shí)系統(tǒng)就會(huì)自動(dòng)創(chuàng)建一個(gè)主線程。
- 在 C# 中,System.Threading.Thread 類(lèi)用于線程的工作。它允許創(chuàng)建并訪問(wèn)多線程應(yīng)用程序中的單個(gè)線程
- 可以使用 Thread 類(lèi)的 CurrentThread 屬性訪問(wèn)線程。
舉例:主線程執(zhí)行
internal class ThreadTest
{
static void Main(string[] args)
{
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("線程ID是:{0},線程名稱(chēng)是:{1}", th.ManagedThreadId, th.Name);
}
}
輸出結(jié)果
線程ID是:1,線程名稱(chēng)是:MainThread
**多線程的創(chuàng)建與管理 **
創(chuàng)建
- 線程是通過(guò)擴(kuò)展 Thread 類(lèi)創(chuàng)建的,然后在構(gòu)造方法中傳入委托對(duì)象。擴(kuò)展的 Thread 類(lèi)調(diào)用 Start() 方法來(lái)開(kāi)始子線程的執(zhí)行
- **子線程不需要傳參使用 **ThreadStart
internal class ThreadTest
{
static void Main(string[] args)
{
// 創(chuàng)建兩個(gè)子線程
Thread t1 = new Thread(new ThreadStart(PrintStr));
Thread t2 = new Thread(new ThreadStart(PrintStr));
t1.Start();
t2.Start();
}
private static void PrintStr()
{
Thread th = Thread.CurrentThread;
Console.WriteLine("線程ID是:{0}", th.ManagedThreadId);
}
}
輸出結(jié)果
線程ID是:7
線程ID是:6
通過(guò)ThreadStart 源碼,可以看到它其實(shí)是一個(gè)委托
**
編輯**
- 如果要向子線程中傳遞參數(shù)則需要使用: ParameterizedThreadStart
- 注意:ParameterizedThreadStart委托的參數(shù)類(lèi)型必須是Object的
internal class ThreadTest
{
static void Main(string[] args)
{
// 創(chuàng)建兩個(gè)子線程
Thread t1 = new Thread(new ParameterizedThreadStart(PrintStrParam));
Thread t2 = new Thread(new ParameterizedThreadStart(PrintStrParam));
t1.Start("我是有參數(shù)1");
t2.Start("我是有參數(shù)2");
}
private static void PrintStrParam(Object obj)
{
Thread th = Thread.CurrentThread;
Console.WriteLine("線程ID是:{0},參數(shù)是:{1}", th.ManagedThreadId,obj);
}
}
輸出結(jié)果
線程ID是:6,參數(shù)是:我是有參數(shù)1
線程ID是:7,參數(shù)是:我是有參數(shù)2
線程的管理與銷(xiāo)毀
- Thread 類(lèi)提供了各種管理線程的方法,下面演示sleep() 方法的使用,用于在一個(gè)特定的時(shí)間暫停線程
- Abort() 方法用于銷(xiāo)毀線程;通過(guò)拋出 threadabortexception 在運(yùn)行時(shí)中止線程。這個(gè)異常不能被捕獲,如果有 finally 塊,控制會(huì)被送至 finally 塊。 注:這個(gè)方法被標(biāo)記過(guò)時(shí)了,雖然依舊可以使用,但推薦使用 CancellationToken 來(lái)代替
internal class ThreadTest
{
static void Main(string[] args)
{
// 創(chuàng)建兩個(gè)子線程
Thread t1 = new Thread(new ThreadStart(printSleep));
t1.Start();
// 主線程睡眠 1 秒
Thread.Sleep(1000);
// 銷(xiāo)毀線程
try
{
t1.Abort();
}
catch (ThreadAbortException e)
{
Console.WriteLine("進(jìn)catch了嗎???");
}
finally
{
Console.WriteLine("進(jìn)finally了嗎???");
}
}
private static void printSleep()
{
for (int i = 0; i < 10; i++)
{
// 睡眠 500 毫秒
Thread.Sleep(500);
Console.WriteLine("輸出數(shù)字:{0}", i);
}
}
}
輸出結(jié)果
輸出數(shù)字:0
Unhandled exception. 輸出數(shù)字:1
System.PlatformNotSupportedException: Thread abort is not supported on this platform.
輸出數(shù)字:2
進(jìn)finally了嗎???
線程同步與鎖
- 所謂同步:是指在某一時(shí)刻只有一個(gè)線程可以訪問(wèn)變量。
- 如果不能確保對(duì)變量的訪問(wèn)是同步的,就會(huì)產(chǎn)生錯(cuò)誤。比如:兩個(gè)人同時(shí)賣(mài)一個(gè)倉(cāng)庫(kù)中的同種 手機(jī),如果不控制就可能出現(xiàn) 超賣(mài)現(xiàn)象 (即賣(mài)出的大于庫(kù)存的)
- c#為同步訪問(wèn)變量提供了一個(gè)非常簡(jiǎn)單的方式,即使用c#語(yǔ)言的關(guān)鍵字 **Lock**,它可以把一段代碼定義為互斥段,互斥段在一個(gè)時(shí)刻內(nèi)只允許一個(gè)線程進(jìn)入執(zhí)行
lock
塊語(yǔ)法:
- 需要注意,傳給**
lock
塊**的參數(shù)不能是值類(lèi)型和string
類(lèi)型,必須是除了string
外的引用類(lèi)型,而且這個(gè)引用類(lèi)型對(duì)象必須是所有線程都能訪問(wèn)到的,否則鎖不住。 - 如果你想保護(hù)一個(gè)類(lèi)的實(shí)例,一般地,你可以使用this;
- 如果你想保護(hù)一個(gè)靜態(tài)變量(如互斥代碼段在一個(gè)靜態(tài)方法內(nèi)部),一般使用類(lèi)名就可以了
- 也可以單獨(dú)創(chuàng)建一個(gè)
object
對(duì)象來(lái)作為指定的鎖對(duì)象
語(yǔ)法如下:
lock(expression)
{
// 代碼邏輯
}
加鎖前案例
internal class ThreadTest
{
static void Main(string[] args)
{
PhoneSale phone=new PhoneSale();
// 創(chuàng)建兩個(gè)子線程
Thread t1 = new Thread(new ThreadStart(phone.SalePhone));
Thread t2 = new Thread(new ThreadStart(phone.SalePhone));
t1.Start();
t2.Start();
}
}
public class PhoneSale
{
// 數(shù)量
private int num = 1;
public void SalePhone()
{
if (num > 0)
{
Thread.Sleep(100);
num--;
Console.WriteLine("賣(mài)出一部手機(jī),還剩下 {0} 個(gè)",num);
}
else
{
Console.WriteLine("賣(mài)完了....");
}
}
}
輸出結(jié)果
賣(mài)出一部手機(jī),還剩下 0 個(gè)
賣(mài)出一部手機(jī),還剩下 -1 個(gè)
**加鎖后案例
**
internal class ThreadTest
{
static void Main(string[] args)
{
PhoneSale phone=new PhoneSale();
// 創(chuàng)建兩個(gè)子線程
Thread t1 = new Thread(new ThreadStart(phone.SalePhone));
Thread t2 = new Thread(new ThreadStart(phone.SalePhone));
t1.Start();
t2.Start();
}
}
public class PhoneSale
{
// 數(shù)量
private int num = 1;
public void SalePhone()
{
lock (this)
{
if (num > 0)
{
Thread.Sleep(100);
num--;
Console.WriteLine("賣(mài)出一部手機(jī),還剩下 {0} 個(gè)", num);
}
else
{
Console.WriteLine("賣(mài)完了....");
}
}
}
}
輸出結(jié)果
賣(mài)出一部手機(jī),還剩下 0 個(gè)
賣(mài)完了....
多線程的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 可以同時(shí)完成多個(gè)任務(wù),使程序的響應(yīng)速度更快
- 多線程技術(shù)解決了多部分代碼同時(shí)執(zhí)行的需求,能夠更好的利用cpu的資源
- 可以設(shè)置每個(gè)任務(wù)的優(yōu)先級(jí)以優(yōu)化程序性能
缺點(diǎn)
- 線程需要占用內(nèi)存,線程越多,占用內(nèi)存也越多
- 多線程需要協(xié)調(diào)和管理,所以需要占用CPU時(shí)間以便跟蹤線程
- 線程之間對(duì)共享資源的訪問(wèn)會(huì)相互影響,必須解決爭(zhēng)用共享資源的問(wèn)題
- 線程太多會(huì)導(dǎo)致控制太復(fù)雜
為什么程序可以多線程執(zhí)行呢? 程序中的多線程與CPU的多線程有什么關(guān)系?
-
目前電腦都是多核多CPU的,一個(gè)CPU在同一時(shí)刻只能運(yùn)行一個(gè)線程,但是多個(gè)CPU在同一時(shí)刻就可以運(yùn)行多個(gè)線程。
-
線程的最大并行數(shù)量上限是CPU核心的數(shù)量,但是,往往電腦運(yùn)行的線程的數(shù)量遠(yuǎn)大于CPU核心的數(shù)量,所以還是需要CPU時(shí)間片的切換
-
CPU運(yùn)行速度太快,硬件處理速度跟不上,所以操作系統(tǒng)進(jìn)行分 ** 時(shí)間片
管理** 。這樣,從宏觀角度來(lái)說(shuō)是多線程并發(fā)的,因?yàn)镃PU速度太快,察覺(jué)不到,看起來(lái)是同一時(shí)刻執(zhí)行了不同的操作
-
cpu
+關(guān)注
關(guān)注
68文章
10904瀏覽量
213023 -
應(yīng)用程序
+關(guān)注
關(guān)注
38文章
3292瀏覽量
57917 -
線程
+關(guān)注
關(guān)注
0文章
505瀏覽量
19758
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論