基本概念
線程
- 被定義為程序的執(zhí)行路徑,也叫執(zhí)行單元
- 線程是輕量級進(jìn)程;使用線程節(jié)省了 CPU 周期的浪費,同時提高了應(yīng)用程序的效率
進(jìn)程
- 是Windows系統(tǒng)中的一個基本概念,它包含著一個運行程序所需要的資源。一個正在運行的應(yīng)用程序在操作系統(tǒng)中被視為一個進(jìn)程
- 一個進(jìn)程可以包括一個或多個線程, 注:至少得有一個線程
- 進(jìn)程之間是相對獨立的,一個進(jìn)程無法訪問另一個進(jìn)程的數(shù)據(jù)
查看當(dāng)前系統(tǒng)中的進(jìn)程
打開任務(wù)管理器,查看當(dāng)前運行的進(jìn)程
編輯
查看當(dāng)前系統(tǒng)中的線程
在任務(wù)管理器里面查詢當(dāng)前總共運行的線程數(shù)
****
編輯****
并行與串行(異步與同步)
- 并行(異步): 多個線程同時執(zhí)行任務(wù)
- 舉例:小明在燒開水的同時去洗菜了
- 串行(同步): 一個任務(wù)執(zhí)行完后才能執(zhí)行下一個
- 舉例:小明在燒開水,等開水燒開后再去洗菜
線程的生命周期
- 新建 :當(dāng)線程實例被創(chuàng)建但 Start 方法未被調(diào)用時的狀況
- 就緒 :當(dāng)線程準(zhǔn)備好運行并等待 CPU 調(diào)度
- 不可運行 :下面的幾種情況下線程是不可運行的:
- 已經(jīng)調(diào)用 Sleep 方法
- 已經(jīng)調(diào)用 Wait 方法
- 通過 I/O 操作阻塞
- 死亡狀態(tài) :當(dāng)線程已完成執(zhí)行或已中止時的狀況
主線程
- 一個進(jìn)程可以包含若干個線程,在進(jìn)程入口執(zhí)行的 第一個線程被視為這個進(jìn)程的主線程 。
- 在 C# 中,都是以Main()方法作為入口的,當(dāng)調(diào)用此方法時系統(tǒng)就會自動創(chuàng)建一個主線程。
- 在 C# 中,System.Threading.Thread 類用于線程的工作。它允許創(chuàng)建并訪問多線程應(yīng)用程序中的單個線程
- 可以使用 Thread 類的 CurrentThread 屬性訪問線程。
舉例:主線程執(zhí)行
internal class ThreadTest
{
static void Main(string[] args)
{
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("線程ID是:{0},線程名稱是:{1}", th.ManagedThreadId, th.Name);
}
}
輸出結(jié)果
線程ID是:1,線程名稱是:MainThread
**多線程的創(chuàng)建與管理 **
創(chuàng)建
- 線程是通過擴展 Thread 類創(chuàng)建的,然后在構(gòu)造方法中傳入委托對象。擴展的 Thread 類調(diào)用 Start() 方法來開始子線程的執(zhí)行
- **子線程不需要傳參使用 **ThreadStart
internal class ThreadTest
{
static void Main(string[] args)
{
// 創(chuàng)建兩個子線程
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
通過ThreadStart 源碼,可以看到它其實是一個委托
**
編輯**
internal class ThreadTest
{
static void Main(string[] args)
{
// 創(chuàng)建兩個子線程
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
線程的管理與銷毀
- Thread 類提供了各種管理線程的方法,下面演示sleep() 方法的使用,用于在一個特定的時間暫停線程
- Abort() 方法用于銷毀線程;通過拋出 threadabortexception 在運行時中止線程。這個異常不能被捕獲,如果有 finally 塊,控制會被送至 finally 塊。 注:這個方法被標(biāo)記過時了,雖然依舊可以使用,但推薦使用 CancellationToken 來代替
internal class ThreadTest
{
static void Main(string[] args)
{
// 創(chuàng)建兩個子線程
Thread t1 = new Thread(new ThreadStart(printSleep));
t1.Start();
// 主線程睡眠 1 秒
Thread.Sleep(1000);
// 銷毀線程
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了嗎???
線程同步與鎖
- 所謂同步:是指在某一時刻只有一個線程可以訪問變量。
- 如果不能確保對變量的訪問是同步的,就會產(chǎn)生錯誤。比如:兩個人同時賣一個倉庫中的同種 手機,如果不控制就可能出現(xiàn) 超賣現(xiàn)象 (即賣出的大于庫存的)
- c#為同步訪問變量提供了一個非常簡單的方式,即使用c#語言的關(guān)鍵字 **Lock**,它可以把一段代碼定義為互斥段,互斥段在一個時刻內(nèi)只允許一個線程進(jìn)入執(zhí)行
lock
塊語法:
- 需要注意,傳給**
lock
塊**的參數(shù)不能是值類型和string
類型,必須是除了string
外的引用類型,而且這個引用類型對象必須是所有線程都能訪問到的,否則鎖不住。 - 如果你想保護(hù)一個類的實例,一般地,你可以使用this;
- 如果你想保護(hù)一個靜態(tài)變量(如互斥代碼段在一個靜態(tài)方法內(nèi)部),一般使用類名就可以了
- 也可以單獨創(chuàng)建一個
object
對象來作為指定的鎖對象
語法如下:
lock(expression)
{
// 代碼邏輯
}
加鎖前案例
internal class ThreadTest
{
static void Main(string[] args)
{
PhoneSale phone=new PhoneSale();
// 創(chuàng)建兩個子線程
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("賣出一部手機,還剩下 {0} 個",num);
}
else
{
Console.WriteLine("賣完了....");
}
}
}
輸出結(jié)果
賣出一部手機,還剩下 0 個
賣出一部手機,還剩下 -1 個
**加鎖后案例
**
internal class ThreadTest
{
static void Main(string[] args)
{
PhoneSale phone=new PhoneSale();
// 創(chuàng)建兩個子線程
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("賣出一部手機,還剩下 {0} 個", num);
}
else
{
Console.WriteLine("賣完了....");
}
}
}
}
輸出結(jié)果
賣出一部手機,還剩下 0 個
賣完了....
多線程的優(yōu)缺點
優(yōu)點
- 可以同時完成多個任務(wù),使程序的響應(yīng)速度更快
- 多線程技術(shù)解決了多部分代碼同時執(zhí)行的需求,能夠更好的利用cpu的資源
- 可以設(shè)置每個任務(wù)的優(yōu)先級以優(yōu)化程序性能
缺點
- 線程需要占用內(nèi)存,線程越多,占用內(nèi)存也越多
- 多線程需要協(xié)調(diào)和管理,所以需要占用CPU時間以便跟蹤線程
- 線程之間對共享資源的訪問會相互影響,必須解決爭用共享資源的問題
- 線程太多會導(dǎo)致控制太復(fù)雜
為什么程序可以多線程執(zhí)行呢? 程序中的多線程與CPU的多線程有什么關(guān)系?
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
cpu
+關(guān)注
關(guān)注
68文章
10769瀏覽量
210428 -
應(yīng)用程序
+關(guān)注
關(guān)注
37文章
3221瀏覽量
57502 -
線程
+關(guān)注
關(guān)注
0文章
502瀏覽量
19613
發(fā)布評論請先 登錄
相關(guān)推薦
Java的線程課程
線程的概念線程其實是控制線程(Thread of control)的簡寫。 控制線程就是程序運行時的路徑,是在一個程序中與其它控制線程無關(guān)的
發(fā)表于 04-10 15:58
?0次下載
JAVA線程實驗
實驗11 線程一、實驗?zāi)康?1. 線程的概念、線程的生命周期。2. 多線程的編程:繼承Thread類與使用Runnable接口。3. 使用多
發(fā)表于 09-23 19:04
?1165次閱讀
多線程編程之Linux線程編程
9.2 Linux線程編程 9.2.1 線程基本編程 這里要講的線程相關(guān)操作都是用戶空間中的線程的操作。在Linux中,一般pthread線程
發(fā)表于 10-18 15:55
?3次下載
多線程好還是單線程好?單線程和多線程的區(qū)別 優(yōu)缺點分析
摘要:如今單線程與多線程已經(jīng)得到普遍運用,那么到底多線程好還是單線程好呢?單線程和多線程的區(qū)別又
發(fā)表于 12-08 09:33
?8.1w次閱讀
線程的實現(xiàn)方式,四線程和八線程的區(qū)別介紹
摘要:線程是程序執(zhí)行流的最小單元。四線程和八線程是線程的兩種表現(xiàn)形式,下面來看看它們之間的區(qū)別以及線程的實現(xiàn)方式。
發(fā)表于 12-08 14:31
?1.2w次閱讀
MFC多線程及線程同步
MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區(qū)別在于工作者線程沒有消息循環(huán),而用戶界面線程有自己的消息隊列和消息循環(huán)。
發(fā)表于 06-01 17:03
?0次下載
什么是線程池 線程池中線程實現(xiàn)復(fù)用的原理
一般建議自定義線程工廠,構(gòu)建線程的時候設(shè)置線程的名稱,這樣就在查日志的時候就方便知道是哪個線程執(zhí)行的代碼。
發(fā)表于 01-29 13:44
?1662次閱讀
核心線程數(shù)和最大線程數(shù)區(qū)別
核心線程數(shù)和最大線程數(shù)區(qū)別 核心線程數(shù)是線程池中一直存在的線程數(shù),不會被回收。最大線程數(shù)是
線程池的線程怎么釋放
從線程分組看,pool名開頭線程占616條,而且waiting狀態(tài)也是616條,這個點就非??梢闪?,我斷定就是這個pool開頭線程池導(dǎo)致的問題。我們先排查為何這個線程池中會有600+的
發(fā)表于 07-31 10:49
?2148次閱讀
線程池基本概念與原理
一、線程池基本概念與原理 1.1 線程池概念及優(yōu)勢 C++線程池簡介 線程池是一種并發(fā)編程技術(shù),它能有效地管理并發(fā)的線程、減少資源占用和提高
核心線程數(shù)和最大線程數(shù)怎么設(shè)置
核心線程數(shù)和最大線程數(shù)是Java線程池中重要的參數(shù),用來控制線程池中線程的數(shù)量和行為。正確地設(shè)置這兩個參數(shù)可以優(yōu)化系統(tǒng)的性能和資源利用率。本
redis多線程還能保證線程安全嗎
Redis是一種使用C語言編寫的高性能鍵值存儲系統(tǒng),它是單線程的,因為使用了多路復(fù)用的方式來處理并發(fā)請求。這樣的實現(xiàn)方式帶來了很好的性能,但同時也引發(fā)了一些線程安全方面的問題。 在Redis中,由于
CPU線程和程序線程的區(qū)別
CPU的線程與程序的線程在概念、作用、實現(xiàn)方式以及性能影響等方面存在顯著差異。以下是對兩者區(qū)別的詳細(xì)闡述,旨在深入探討這一技術(shù)話題。
評論