一、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)系本人修改,謝謝?。?! |
|
|
來自: 新進小設(shè)計 > 《待分類》