小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

.NET異步和多線程系列(二)- Thread和ThreadPool

 新進小設(shè)計 2021-03-19

一、Thread類

C#里面的多線程:Thread類是C#語言對線程對象的一個封裝。

首先看下如何開啟線程,執(zhí)行委托的內(nèi)容:

/// <summary>/// 一個比較耗時耗資源的私有方法/// </summary>private void DoSomethingLong(string name)
{
    Console.WriteLine($"****************DoSomethingLong Start  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} " +$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");long lResult = 0;for (int i = 0; i < 1_000_000_000; i++)
    {
        lResult += i;
    }
    Thread.Sleep(2000);
    Console.WriteLine($"****************DoSomethingLong   End  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} " +$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
}
/// <summary>/// 多線程 Thread類是.NET Framework 1.0的時候出現(xiàn)的/// Thread:C#對線程對象的一個封裝/// </summary>private void btnThread_Click(object sender, EventArgs e)
{
    Console.WriteLine($"****************btnThread_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} " +$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

    {
        ParameterizedThreadStart method = o => this.DoSomethingLong("btnThread_Click");
        Thread thread = new Thread(method);
        thread.Start("浪子天涯");//開啟線程,執(zhí)行委托的內(nèi)容    }

    Console.WriteLine($"****************btnThread_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} " +$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}

線程等待、線程優(yōu)先級、前臺線程和后臺線程:

{
    ThreadStart method = () =>{
        Thread.Sleep(5000);this.DoSomethingLong("btnThread_Click");
        Thread.Sleep(5000);
    };
    Thread thread = new Thread(method);
    thread.Start(); //開啟線程,執(zhí)行委托的內(nèi)容//該花括號內(nèi)的這些方法已經(jīng)被微軟拋棄了,建議不要去用    {//thread.Suspend(); //暫停//thread.Resume();//恢復(fù)    真的不該要的,暫停不一定馬上暫停;讓線程操作太復(fù)雜了//thread.Abort();//線程是計算機資源,程序想停下線程,只能向操作系統(tǒng)通知(線程拋異常),//會有延時/不一定能真的停下來//Thread.ResetAbort();    }//1等待while (thread.ThreadState != ThreadState.Stopped)
    {
        Thread.Sleep(200); //當(dāng)前線程休息200ms    }//2 Join等待thread.Join(); //運行這句代碼的線程,等待thread的完成thread.Join(1000); //最多等待1000msConsole.WriteLine("這里是線程執(zhí)行完之后才操作。。。");//最高優(yōu)先級:優(yōu)先執(zhí)行,但不代表優(yōu)先完成看,甚至說極端情況下,還有意外發(fā)生,不能通過這個來控制線程的執(zhí)行先后順序thread.Priority = ThreadPriority.Highest;//是否是后臺線程 默認是falsethread.IsBackground = false; //默認是false 前臺線程,進程關(guān)閉,線程需要計算完后才退出//thread.IsBackground = true;//關(guān)閉進程,線程退出}

下面來看下Thread類的使用:

基于Thread封裝一個帶有回調(diào)的

/// <summary>/// 基于Thread封裝一個回調(diào)/// 回調(diào):啟動子線程執(zhí)行動作A--不阻塞--A執(zhí)行完后子線程會執(zhí)行動作B/// </summary>/// <param name="threadStart">多線程執(zhí)行的操作</param>/// <param name="actionCallback">線程完成后,回調(diào)的動作</param>private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallback)
{//Thread thread = new Thread(threadStart);//thread.Start();//thread.Join(); //錯了,因為方法被阻塞了//actionCallback.Invoke();ThreadStart method = new ThreadStart(() =>{
        threadStart.Invoke();
        actionCallback.Invoke();
    });new Thread(method).Start();
}
{
    ThreadStart threadStart = () => this.DoSomethingLong("btnThread_Click");
    Action actionCallBack = () =>{
        Thread.Sleep(2000);
        Console.WriteLine($"This is Calllback {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    };this.ThreadWithCallBack(threadStart, actionCallBack);
}

基于Thread封裝一個帶有返回值的

/// <summary>/// 基于Thread封裝一個帶有返回值的/// 1 異步,非阻塞的/// 2 還能獲取到最終計算結(jié)果/// /// 既要不阻塞,又要計算結(jié)果?不可能!故此處返回一個委托,當(dāng)外部需要使用結(jié)果的時候再阻塞,此時可能已經(jīng)計算完了。/// </summary>private Func<T> ThreadWithReturn<T>(Func<T> func)
{
    T t = default(T);
    ThreadStart threadStart = new ThreadStart(() =>{
        t = func.Invoke();
    });
    Thread thread = new Thread(threadStart);
    thread.Start();return new Func<T>(() =>{
        thread.Join();//thread.ThreadStatereturn t;
    });
}
{
    Func<int> func = () =>{
        Thread.Sleep(5000);return DateTime.Now.Year;
    };
    Func<int> funcThread = this.ThreadWithReturn(func);//非阻塞Console.WriteLine("do something 1");
    Console.WriteLine("do something 2");
    Console.WriteLine("do something 3");int iResult = funcThread.Invoke();//阻塞}

控制線程的數(shù)量(僅供參考):

{
    List<Thread> threads = new List<Thread>();for (int i = 0; i < 100; i++)
    {if (threads.Count(t => t.ThreadState == ThreadState.Running) < 10)
        {
            Thread thread = new Thread(new ThreadStart(() => { }));
            thread.Start();
            threads.Add(thread);
        }else{
            Thread.Sleep(200);
        }
    }
}

二、ThreadPool類

由于Thread類功能繁多,反而用不好--就像給4歲小孩一把熱武器,反而會造成更大的傷害。而且對線程數(shù)量也是沒有管控的。故微軟在.NET Framework 2.0推出來ThreadPool線程池

如果某個對象創(chuàng)建和銷毀代價比較高,同時這個對象還可以反復(fù)使用的,就需要一個池子。

保存多個這樣的對象,需要用的時候從池子里面獲?。挥猛曛蟛挥娩N毀,放回池子;(享元模式)

節(jié)約資源提升性能;此外,還能管控總數(shù)量,防止濫用;

ThreadPool的線程都是后臺線程。

下面我們直接來看下相關(guān)代碼:

/// <summary>/// ThreadPool線程池/// 由于Thread類功能繁多,反而用不好--就像給4歲小孩一把熱武器,反而會造成更大的傷害/// 對線程數(shù)量是沒有管控的/// /// 線程池是.NET Framework 2.0推出來的/// 如果某個對象創(chuàng)建和銷毀代價比較高,同時這個對象還可以反復(fù)使用的,就需要一個池子/// 保存多個這樣的對象,需要用的時候從池子里面獲取;用完之后不用銷毀,放回池子;(享元模式)/// 節(jié)約資源提升性能;此外,還能管控總數(shù)量,防止濫用;/// /// ThreadPool的線程都是后臺線程/// /// 大家課后可以試試,基于ThreadPool去封裝回調(diào)--返回值的/// </summary>private void btnThreadPool_Click(object sender, EventArgs e)
{
    Console.WriteLine($"****************btnThreadPool_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} " +$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");//啟動線程    {
        ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("btnThreadPool_Click1"));
        ThreadPool.QueueUserWorkItem(o => this.DoSomethingLong("btnThreadPool_Click2"), "浪子天涯");
    }

    {
        ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
        Console.WriteLine($"當(dāng)前電腦最大workerThreads={workerThreads} 最大completionPortThreads={completionPortThreads}");

        ThreadPool.GetMinThreads(out int workerThreadsMin, out int completionPortThreadsMin);
        Console.WriteLine($"當(dāng)前電腦最小workerThreads={workerThreadsMin} 最大completionPortThreads={completionPortThreadsMin}");//設(shè)置的線程池數(shù)量是進程全局的(慎用,一般不用)//委托異步調(diào)用--Task--Parrallel--async/await 全部都是線程池的線程//直接new Thread不受這個數(shù)量限制的(但是會占用線程池的線程數(shù)量)ThreadPool.SetMaxThreads(8, 8); //設(shè)置的最大值,必須大于CPU核數(shù),否則設(shè)置無效ThreadPool.SetMinThreads(2, 2);
        Console.WriteLine("====================設(shè)置線程池數(shù)量最大最小====================");

        ThreadPool.GetMaxThreads(out int workerThreads1, out int completionPortThreads1);
        Console.WriteLine($"當(dāng)前電腦最大workerThreads={workerThreads1} 最大completionPortThreads={completionPortThreads1}");

        ThreadPool.GetMinThreads(out int workerThreadsMin1, out int completionPortThreadsMin1);
        Console.WriteLine($"當(dāng)前電腦最大workerThreads={workerThreadsMin1} 最大completionPortThreads={completionPortThreadsMin1}");
    }//線程等待    {
        ManualResetEvent mre = new ManualResetEvent(false);//false---關(guān)閉---Set打開---true---WaitOne就能通過//true---打開--ReSet關(guān)閉---false--WaitOne就只能等待ThreadPool.QueueUserWorkItem(o =>{this.DoSomethingLong("btnThreadPool_Click1");
            mre.Set();
        });
        Console.WriteLine("Do Something 1");
        Console.WriteLine("Do Something 2");
        Console.WriteLine("Do Something 3");

        mre.WaitOne();
        Console.WriteLine("任務(wù)已經(jīng)完成了。。。");
    }//寫多線程的時候有這么一種說法:不要阻塞線程池里面的線程。//下面是一個死鎖的例子    {
        ThreadPool.SetMaxThreads(8, 8);
        ManualResetEvent mre = new ManualResetEvent(false);for (int i = 0; i < 10; i++)
        {int k = i; //此處必須聲明一個變量存放i的值,不能直接使用i變量,否則會有問題ThreadPool.QueueUserWorkItem(t =>{
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId.ToString("00")} show {k}");if (k == 9) //設(shè)置了最多只允許8個線程,但此處是9,導(dǎo)致死鎖了                {
                    mre.Set(); //開關(guān)打開                }else{
                    mre.WaitOne(); //線程等待,阻塞                }
            });
        }if (mre.WaitOne()) //開關(guān)沒打開,一直等待,死鎖了        {
            Console.WriteLine("任務(wù)全部執(zhí)行成功!");
        }
    }

    Console.WriteLine($"****************btnThreadPool_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} " +$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}

Demo源碼:

鏈接:https://pan.baidu.com/s/1wVscaka37emNGz9x-rm0qA

此文由博主精心撰寫轉(zhuǎn)載請保留此原文鏈接:https://www.cnblogs.com/xyh9039/p/13550714.html

版權(quán)聲明:如有雷同純屬巧合,如有侵權(quán)請及時聯(lián)系本人修改,謝謝?。?!

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多