0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是線程

汽車電子技術(shù) ? 來源:程序猿知秋 ? 作者: 程序猿知秋 ? 2023-01-20 15:17 ? 次閱讀

基本概念

線程

  • 被定義為程序的執(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)程無法訪問另一個(gè)進(jìn)程的數(shù)據(jù)

查看當(dāng)前系統(tǒng)中的進(jìn)程

微信截圖_20230105161930.png

打開任務(wù)管理器,查看當(dāng)前運(yùn)行的進(jìn)程

編輯

查看當(dāng)前系統(tǒng)中的線程

在任務(wù)管理器里面查詢當(dāng)前總共運(yùn)行的線程數(shù)

****微信截圖_20230105161930.png

編輯****

并行與串行(異步與同步)

  • 并行(異步): 多個(gè)線程同時(shí)執(zhí)行任務(wù)
    • 舉例:小明在燒開水的同時(shí)去洗菜了
  • 串行(同步): 一個(gè)任務(wù)執(zhí)行完后才能執(zhí)行下一個(gè)
    • 舉例:小明在燒開水,等開水燒開后再去洗菜

線程的生命周期

  • 新建 :當(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 方法
    • 通過 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 類用于線程的工作。它允許創(chuàng)建并訪問多線程應(yīng)用程序中的單個(gè)線程
  • 可以使用 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)建

  • 線程是通過擴(kuò)展 Thread 類創(chuàng)建的,然后在構(gòu)造方法中傳入委托對(duì)象。擴(kuò)展的 Thread 類調(diào)用 Start() 方法來開始子線程的執(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

通過ThreadStart 源碼,可以看到它其實(shí)是一個(gè)委托

**微信截圖_20230105161930.png

編輯**

  • 如果要向子線程中傳遞參數(shù)則需要使用: ParameterizedThreadStart
  • 注意:ParameterizedThreadStart委托的參數(shù)類型必須是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

線程的管理與銷毀

  • Thread 類提供了各種管理線程的方法,下面演示sleep() 方法的使用,用于在一個(gè)特定的時(shí)間暫停線程
  • Abort() 方法用于銷毀線程;通過拋出 threadabortexception 在運(yùn)行時(shí)中止線程。這個(gè)異常不能被捕獲,如果有 finally 塊,控制會(huì)被送至 finally 塊。 注:這個(gè)方法被標(biāo)記過時(shí)了,雖然依舊可以使用,但推薦使用 CancellationToken 來代替
internal class ThreadTest
{
  static void Main(string[] args)
  {
    // 創(chuàng)建兩個(gè)子線程
    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了嗎???

線程同步與鎖

  • 所謂同步:是指在某一時(shí)刻只有一個(gè)線程可以訪問變量。
  • 如果不能確保對(duì)變量的訪問是同步的,就會(huì)產(chǎn)生錯(cuò)誤。比如:兩個(gè)人同時(shí)賣一個(gè)倉庫中的同種 手機(jī),如果不控制就可能出現(xiàn) 超賣現(xiàn)象 (即賣出的大于庫存的)
  • c#為同步訪問變量提供了一個(gè)非常簡單的方式,即使用c#語言的關(guān)鍵字 **Lock**,它可以把一段代碼定義為互斥段,互斥段在一個(gè)時(shí)刻內(nèi)只允許一個(gè)線程進(jìn)入執(zhí)行

lock塊語法:

  • 需要注意,傳給**lock塊**的參數(shù)不能是值類型和string類型,必須是除了string外的引用類型,而且這個(gè)引用類型對(duì)象必須是所有線程都能訪問到的,否則鎖不住。
  • 如果你想保護(hù)一個(gè)類的實(shí)例,一般地,你可以使用this;
  • 如果你想保護(hù)一個(gè)靜態(tài)變量(如互斥代碼段在一個(gè)靜態(tài)方法內(nèi)部),一般使用類名就可以了
  • 也可以單獨(dú)創(chuàng)建一個(gè)object對(duì)象來作為指定的鎖對(duì)象

語法如下:

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("賣出一部手機(jī),還剩下 {0} 個(gè)",num);
    }
    else
    {
      Console.WriteLine("賣完了....");
    }
  }
}

輸出結(jié)果

賣出一部手機(jī),還剩下 0 個(gè)
賣出一部手機(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("賣出一部手機(jī),還剩下 {0} 個(gè)", num);
      }
      else
      {
        Console.WriteLine("賣完了....");
      }
    }
  }
}

輸出結(jié)果

賣出一部手機(jī),還剩下 0 個(gè)
賣完了....

多線程的優(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ì)共享資源的訪問會(huì)相互影響,必須解決爭用共享資源的問題
  • 線程太多會(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í)間片

    管理** 。這樣,從宏觀角度來說是多線程并發(fā)的,因?yàn)镃PU速度太快,察覺不到,看起來是同一時(shí)刻執(zhí)行了不同的操作

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10698

    瀏覽量

    209328
  • 應(yīng)用程序
    +關(guān)注

    關(guān)注

    37

    文章

    3198

    瀏覽量

    57356
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    501

    瀏覽量

    19580
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Java的線程課程

    線程的概念線程其實(shí)是控制線程(Thread of control)的簡寫。 控制線程就是程序運(yùn)行時(shí)的路徑,是在一個(gè)程序中與其它控制線程無關(guān)的
    發(fā)表于 04-10 15:58 ?0次下載

    JAVA線程實(shí)驗(yàn)

    實(shí)驗(yàn)11 線程一、實(shí)驗(yàn)?zāi)康?1. 線程的概念、線程的生命周期。2. 多線程的編程:繼承Thread類與使用Runnable接口。3. 使用多
    發(fā)表于 09-23 19:04 ?1157次閱讀

    線程編程之Linux線程編程

    9.2 Linux線程編程 9.2.1 線程基本編程 這里要講的線程相關(guān)操作都是用戶空間中的線程的操作。在Linux中,一般pthread線程
    發(fā)表于 10-18 15:55 ?3次下載

    線程好還是單線程好?單線程和多線程的區(qū)別 優(yōu)缺點(diǎn)分析

    摘要:如今單線程與多線程已經(jīng)得到普遍運(yùn)用,那么到底多線程好還是單線程好呢?單線程和多線程的區(qū)別又
    發(fā)表于 12-08 09:33 ?8.1w次閱讀

    線程的實(shí)現(xiàn)方式,四線程和八線程的區(qū)別介紹

    摘要:線程是程序執(zhí)行流的最小單元。四線程和八線程線程的兩種表現(xiàn)形式,下面來看看它們之間的區(qū)別以及線程的實(shí)現(xiàn)方式。
    發(fā)表于 12-08 14:31 ?1.2w次閱讀

    MFC多線程線程同步

    MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區(qū)別在于工作者線程沒有消息循環(huán),而用戶界面線程有自己的消息隊(duì)列和消息循環(huán)。
    發(fā)表于 06-01 17:03 ?0次下載

    什么是線程線程池中線程實(shí)現(xiàn)復(fù)用的原理

    一般建議自定義線程工廠,構(gòu)建線程的時(shí)候設(shè)置線程的名稱,這樣就在查日志的時(shí)候就方便知道是哪個(gè)線程執(zhí)行的代碼。
    發(fā)表于 01-29 13:44 ?1596次閱讀

    線程線程

    線程池通常用于服務(wù)器應(yīng)用程序。 每個(gè)傳入請(qǐng)求都將分配給線程池中的一個(gè)線程,因此可以異步處理請(qǐng)求,而不會(huì)占用主線程,也不會(huì)延遲后續(xù)請(qǐng)求的處理
    的頭像 發(fā)表于 02-28 09:53 ?667次閱讀
    多<b class='flag-5'>線程</b>之<b class='flag-5'>線程</b>池

    什么是線程安全?如何理解線程安全?

    在多線程編程中,線程安全是必須要考慮的因素。
    的頭像 發(fā)表于 05-30 14:33 ?1845次閱讀
    什么是<b class='flag-5'>線程</b>安全?如何理解<b class='flag-5'>線程</b>安全?

    核心線程數(shù)和最大線程數(shù)區(qū)別

    核心線程數(shù)和最大線程數(shù)區(qū)別 核心線程數(shù)是線程池中一直存在的線程數(shù),不會(huì)被回收。最大線程數(shù)是
    的頭像 發(fā)表于 06-01 09:33 ?7352次閱讀

    線程池的線程怎么釋放

    線程分組看,pool名開頭線程占616條,而且waiting狀態(tài)也是616條,這個(gè)點(diǎn)就非??梢闪?,我斷定就是這個(gè)pool開頭線程池導(dǎo)致的問題。我們先排查為何這個(gè)線程池中會(huì)有600+的
    發(fā)表于 07-31 10:49 ?2066次閱讀
    <b class='flag-5'>線程</b>池的<b class='flag-5'>線程</b>怎么釋放

    線程池基本概念與原理

    一、線程池基本概念與原理 1.1 線程池概念及優(yōu)勢 C++線程池簡介 線程池是一種并發(fā)編程技術(shù),它能有效地管理并發(fā)的線程、減少資源占用和提高
    的頭像 發(fā)表于 11-10 10:24 ?408次閱讀

    核心線程數(shù)和最大線程數(shù)怎么設(shè)置

    核心線程數(shù)和最大線程數(shù)是Java線程池中重要的參數(shù),用來控制線程池中線程的數(shù)量和行為。正確地設(shè)置這兩個(gè)參數(shù)可以優(yōu)化系統(tǒng)的性能和資源利用率。本
    的頭像 發(fā)表于 12-01 13:50 ?7432次閱讀

    redis多線程還能保證線程安全嗎

    Redis是一種使用C語言編寫的高性能鍵值存儲(chǔ)系統(tǒng),它是單線程的,因?yàn)槭褂昧硕嗦窂?fù)用的方式來處理并發(fā)請(qǐng)求。這樣的實(shí)現(xiàn)方式帶來了很好的性能,但同時(shí)也引發(fā)了一些線程安全方面的問題。 在Redis中,由于
    的頭像 發(fā)表于 12-05 10:28 ?1346次閱讀

    CPU線程和程序線程的區(qū)別

    CPU的線程與程序的線程在概念、作用、實(shí)現(xiàn)方式以及性能影響等方面存在顯著差異。以下是對(duì)兩者區(qū)別的詳細(xì)闡述,旨在深入探討這一技術(shù)話題。
    的頭像 發(fā)表于 09-02 11:18 ?335次閱讀