C#多線程ThreadPool類的使用(一)

前面我們介紹了Thread類的使用,此類在。NET1.0版本的時候就有了,其內部含有大量的方法和屬性。使用起來略有繁瑣,爲了提高使用多線程的效率,杜絕濫用多線程,.NET提出了ThreadPool也就是線程池的概念。

何爲ThreadPool線程池?
實際上就是專門放置線程的池子,它是一個類,此類分裝了Thread類中的一些方法和屬性,使用戶使用起來更加的快捷。此外它的使用效率高,需要的時候從池子裏面分配線程,不用的話銷燬還原線程。如此便能夠提升資源,提高效率。

一、ThreadPool類

ThreadPool類中有比較多的方法和屬性。其中使用較爲頻繁的如下:

public static bool QueueUserWorkItem(WaitCallback callBack);  //方法入隊線程池,排隊進入成功則返回true,否則爲false並有異常
public static bool QueueUserWorkItem(WaitCallback callBack, object state); //與上述方法同理,state爲要相關聯的數據
public static void GetMaxThreads(out int workerThreads, out int completionPortThreads);  //獲取最大線程數,包括woeker輔助線程和completionPort異步IO線程
public static void GetMinThreads(out int workerThreads, out int completionPortThreads); //獲取最小線程數
public static void GetAvailableThreads(out int workerThreads, out int completionPortThreads);  //獲取當前有效可用的線程數
public static bool SetMaxThreads(int workerThreads, int completionPortThreads);  //設置最大線程數,注意不能比CPU核數小,否則設置不成功
public static bool SetMinThreads(int workerThreads, int completionPortThreads);  //設置最小線程數,注意不能比CPU核數小,否則設置不成功

如下代碼:

int workerThreads=0,completionPortThreads=0;
ThreadPool.GetMaxThreads(out workerThreads,out completionPortThreads);

Console.WriteLine("當前線程池最大workerTreads數目爲{0},最大conpletionPortThreads數目爲{1}",workerThreads,completionPortThreads);//1023,1000

ThreadPool.GetMinThreads(out workerThreads,out completionPortThreads);

Console.WriteLine("當前線程池最小workerTreads數目爲{0},最小conpletionPortThreads數目爲{1}", workerThreads, completionPortThreads);//4,4

ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);  //返回可用的線程數目,輔助線程和異步IO數目

Console.WriteLine("當前線程池可用workerTreads數目爲{0},可用conpletionPortThreads數目爲{1}", workerThreads, completionPortThreads);//4,4

//設置的線程池的線程數量是進程全局的,
//委託異步調用--Task--Parrallel--async/await 全部都是線程池的線程
//直接new Thread不受這個數量限制的(但是會佔用線程池的線程數量)
ThreadPool.SetMaxThreads(8,8);   //可以設置最大線程,分爲worker線程和completionPort線程,數值不能小於CPU核數否無效
ThreadPool.SetMinThreads(2,2);   //可以設置最小線程,同樣分爲worker和conpletionPort線程

輸出結果爲:
在這裏插入圖片描述

二、線程池開啓與方法入隊

線程池中實際上是有隊列的,隊列中存放的是排隊的待執行的方法,線程池會調度這些方法在不同的線程中執行已達到效率最大化。
下面演示如何開啓線程池和方法入隊。

#region   //兩個共用方法用作調用
public void doSomething1(string name)  //定義一個方法名爲doSomething1()
{
    Console.WriteLine("doSometing1方法調用開始");

    Thread.Sleep(2000);                //將當前的線程暫停2000ms即2秒

    //輸出調用方名稱+當前線程名+本方法標識
    Console.WriteLine("用:" + name + "在" + Thread.CurrentThread.ManagedThreadId.ToString("00") + "線程中執行方法1\n");
}

public void doSomething2(string name)  //定義一個方法名爲doSomething2()
{
    Console.WriteLine("doSometing2方法調用開始");

    Thread.Sleep(2000);               //將當前的線程暫停2000ms即2秒

    //輸出調用方名稱+當前線程名+本方法標識
    Console.WriteLine("用:" + name + "在" + Thread.CurrentThread.ManagedThreadId.ToString("00") + "線程中執行方法2\n");
}
#endregion

接着將項目的輸出設置爲控制檯輸出:
在這裏插入圖片描述
輸入以下代碼:

#region //ThreadPool基本使用
private void button1_Click(object sender, EventArgs e)   //綁定按鈕點擊事件
{
    Console.WriteLine("線程池演示開始,當前主線程爲:"+Thread.CurrentThread.ManagedThreadId);

    #region   //如何開啓線程
    //QueueUserWorkItem()方法接受的參數爲WaitCallback委託,他的定義爲:public delegate void WaitCallback(object state);
    ThreadPool.QueueUserWorkItem(o => this.doSomething1("第1個進入線程池隊列的方法"));     //參數爲WaitCallback委託,它是有參的
    ThreadPool.QueueUserWorkItem(o=>this.doSomething2("第2個進入線程池隊列的方法"),"C#自學"); //調用QueueUserWorkItem()方法的兩個參數重載方法
    Console.WriteLine("兩個方法已經進入線程池裏");
    #endregion

}
#endregion

上述代碼點擊運行後,結果如下:
在這裏插入圖片描述
從上面的結果我們可以看出,由於多線程的作用,主線程沒有阻塞,首先輸出“線程池演示開始,當前主線程爲:9”,接着兩個方法入隊,輸出“兩個方法已經進入線程池裏”,此時調用主線程執行完畢,線程編號爲9,接着線程池裏會分配線程執行入隊的兩個委託,一個在線程10裏,一個在線程11裏。兩個並行處理,最終結束。

三、ThreadPool等待

前面提到過Thread線程等待使用Join()方法可以實現,或者使用while循環判斷thread.ThreadState的狀態值是否爲ThreadState.Stopped,那麼線程池中的等待不同。具體如下:

#region
private void button2_Click(object sender, EventArgs e)
{
    //public ManualResetEvent(bool initialState);  //如果initialState如果爲true,則將初始狀態設置爲終止;如果爲 false,則將初始狀態設置爲非終止。
    ManualResetEvent mre = new ManualResetEvent(false);
    //false---關閉,Set()打開---true---WaitOne就能通過
    //true--打開--ReSet關閉--false---WaitOne就只能等待
    
    //等待方式2:bool Isfinish = false;               //也可以使用這種比較簡單的方式
    ThreadPool.QueueUserWorkItem(o=>                //多線程針對的是方法來說的,對於一個方法內部的語句執行順序仍然是按順序來的
    {
        doSomething1("ThreadPool線程池中等待");
        mre.Set();  //開啓,下面的mre.WaitOne就會等待完成,後才能執行最後的代碼
        Console.WriteLine("1");
        Console.WriteLine("2");
        Console.WriteLine("3");
        Console.WriteLine("4");
        //等待方式2:Isfinish = true;
    });
    //等待方式2:while(!Isfinish);   //直接判斷Isfinish是否爲true就行了。
    mre.WaitOne();   //WaitOne()方法依賴於mre是否爲true,爲true纔有效,會等待,否則無效不等待
    //mre.WaitOne(2000);  //最多等待2秒,超過不等
    Console.WriteLine("執行完畢");
}
#endregion

執行結果如下:
在這裏插入圖片描述
由上面的結果我們可以開出,由於WaitOne的作用,且mre爲true使之線程等待開啓,所以一開始等待被調函數的順序執行完畢後才執行在“執行完畢”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章