C# 多線程


進程和線程

打開任務管理器可以看到正在運行的進程。

進程是什么?

對於用戶來說:進程是程序的一次動態執行過程

對於操作系統來說:進程是操作系統分配資源的基本單位,也是最小單位

為什么會有進程?

CPU一次只能處理一個程序,CPU速度很快,而內存很慢,所以CPU會有大量的時間都是空閑的。而CPU又是很昂貴的,為了解決浪費CPU的情況,就出現了中斷處理,將程序分成一小片一小片的,這個進程執行一點,那個進程執行一點。雖然在內部進程的執行是一段一段的,但是CPU的速度很快的(速度都是納秒級別的),所以我們是感受不到進程執行過程中的停頓的。

在操作系統中引入進程,是為了實現多個程序的並發執行。傳統的程序不能與其他程序並發執行,只有在為之創建進程后,才能與其他程序(進程)並發執行。

線程

線程(Thread)是進程中的基本執行單元,是操作系統分配CPU時間的基本單位,一個進程可以包含若干個線程,在進程入口執行的第一個線程被視為這個進程的主線程。在.NET應用程序中,都是以Main()方法作為入口的,當調用此方法時系統就會自動創建一個主線程。

多線程

多線程的優點

可以同時完成多個任務;可以使程序的響應速度更快;可以讓占用大量處理時間的任務或當前沒有進行處理的任務定期將處理時間讓給別的任務;可以隨時停止任務;可以設置每個任務的優先級以優化程序性能。

多線程的缺點

線程也是程序,所以線程需要占用內存,線程越多,占用內存也越多。

多線程需要協調和管理,所以需要占用CPU時間以便跟蹤線程。

線程之間對共享資源的訪問會相互影響,必須解決爭用共享資源的問題。

線程太多會導致控制太復雜,最終可能造成很多程序缺陷。

創建線程執行無參委托

public delegate void ThreadStart()

靜態方法

/// <summary>無參的方法</summary>
static void Func1()
{
    Console.WriteLine("這是無參的方法");
}

Thread thread = new Thread(new ThreadStart(Func1));
//調用Start方法執行線程
thread.Start();
Console.ReadKey();

實例方法

Thread thread = new Thread(new ThreadStart(new TestClass().Func1));
//調用Start方法執行線程
thread.Start();
Console.ReadKey();

class TestClass
{
    /// <summary>無參的方法</summary>
    public void Func1()
    {
        Console.WriteLine("這是無參的實例方法");
    }
}

匿名方法和Lambda表達式

Thread thread1 = new Thread(delegate () {
    Console.WriteLine("匿名委托");
});
Thread thread2 = new Thread(()=> {
    Console.WriteLine("Lambda表達式");
});
thread1.Start();
thread2.Start();
Console.ReadKey();

 這里發現Lambda反而先執行是因為開了兩個線程同時執行的。

創建線程執行有參數的委托

public delegate void ParameterizedThreadStart(Object obj)

ParameterizedThreadStart委托的參數類型必須是Object的。

//通過ParameterizedThreadStart創建線程
Thread thread = new Thread(new ParameterizedThreadStart(Func1));
//給方法傳值
thread.Start("這是一個有參數的委托");
Console.ReadKey();

/// <summary>
/// 創建有參的方法
/// 注意:方法里面的參數類型必須是Object類型
/// </summary>
/// <param name="obj"></param>
static void Func1(object obj)
{
    Console.WriteLine(obj);
}

線程的屬性

//獲取正在運行的線程
Thread thread = Thread.CurrentThread;
//獲取當前線程的唯一標識符
int id = thread.ManagedThreadId;
//獲取當前線程的狀態
ThreadState state = thread.ThreadState;
//獲取當前線程的優先級
ThreadPriority priority = thread.Priority;

Thread thread2 = new Thread(() =>
{
    Console.WriteLine("111");
});


Console.WriteLine($"主線程ID:{id}");
Console.WriteLine($"主線程狀態:{state}");
Console.WriteLine($"主線程優先級:{priority}");

Console.WriteLine($"thread2 ID:{thread2.ManagedThreadId}");
Console.WriteLine($"thread2 狀態:{thread2.ThreadState}");
Console.WriteLine($"thread2 優先級:{thread2.Priority}");
thread2.Start();
Console.WriteLine($"thread2 狀態:{thread2.ThreadState}");
Console.ReadKey();

前台線程和后台線程

介紹

前台線程:只有所有的前台線程都結束,應用程序才能結束。默認情況下創建的線程都是前台線程
后台線程:只要所有的前台線程結束,后台線程自動結束。通過Thread.IsBackground設置后台線程。必須在調用Start方法之前設置線程的類型,否則一旦線程運行,將無法改變其類型。

通過BeginXXX方法運行的線程都是后台線程。

使用

//演示前台、后台線程
TestClass f = new TestClass(10);
//創建前台線程
Thread fThread = new Thread(new ThreadStart(f.RunLoop));
//給線程命名
fThread.Name = "前台線程";

TestClass b = new TestClass(20);
//創建后台線程
Thread bThread = new Thread(new ThreadStart(b.RunLoop));
bThread.Name = "后台線程";
//設置為后台線程
bThread.IsBackground = true;

//啟動線程
fThread.Start();
bThread.Start();

class TestClass
{
    private int Count;
    public TestClass(int count)
    {
        this.Count = count;
    }
    public void RunLoop()
    {
        //獲取當前線程的名稱
        string threadName = Thread.CurrentThread.Name;
        for (int i = 0; i < Count; i++)
        {
            Console.WriteLine($"{threadName}計數:{i}");
            //線程休眠500毫秒
            Thread.Sleep(1000);
        }
        Console.WriteLine("{0}完成計數", threadName);

    }
}

 

 我們發現前台線程執行完了不等待后台線程執行完控制台程序就結束了。

我們給bThread不設置為后台線程再輸出看看:

線程同步

是指在某一時刻只有一個線程可以訪問變量。

lock(expression)
{
   statement_block
}

expression代表你希望跟蹤的對象:
如果你想保護一個類的實例,一般地,你可以使用this;
如果你想保護一個靜態變量(如互斥代碼段在一個靜態方法內部),一般使用類名就可以了
而statement_block就算互斥段的代碼,這段代碼在一個時刻內只可能被一個線程執行。

搶紅包的案例(發了三個包)

RedBao red = new RedBao();
//五個人同時搶
Thread t1 = new Thread(new ThreadStart(red.Qiang));
Thread t2 = new Thread(new ThreadStart(red.Qiang));
Thread t3 = new Thread(new ThreadStart(red.Qiang));
Thread t4 = new Thread(new ThreadStart(red.Qiang));
Thread t5 = new Thread(new ThreadStart(red.Qiang));

//啟動線程
t1.Start();
t2.Start();
t3.Start();
t4.Start();
t5.Start();
Console.ReadKey();

class RedBao
{
    public int count = 3;
    public void Qiang()
    {
        int temp = count;
        if (temp > 0)//判斷是否還有庫存
        {
            Thread.Sleep(1000);
            count -= 1;
            Console.WriteLine("恭喜你搶到了0.01元");
        }
        else
        {
            Console.WriteLine("太慢了,紅包已被搶光");
        }
    }
}

 

發了三個搶走了五個肯定有問題,我們加上線程同步來解決(修改下Qiang方法): 

public void Qiang()
    {
        lock (this)
        {
            int temp = count;
            if (temp > 0)//判斷是否還有庫存
            {
                Thread.Sleep(1000);
                count -= 1;
                Console.WriteLine("恭喜你搶到了0.01元");
            }
            else
            {
                Console.WriteLine("太慢了,紅包已被搶光");
            }
        }
    }

 原文:https://www.cnblogs.com/dotnet261010/p/6159984.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM