[.net 面向對象程序設計進階] (16) 多線程(Multithreading)(一) 利用多線程提升程序性能(上)html
本節導讀:編程
隨着硬件和網絡的高速發展,爲多線程(Multithreading)處理並行任務,提供了有利條件。服務器
其實咱們每時每刻都在享受多線程帶來的便利,多核處理器多線程工做、Windows操做系統、Web服務器都在使用多線程工做。網絡
使用多線程直接提升了程序的執行效率,所以學習多線程對提升程序運行能力很是必要,本節主要介紹多線程原理及.NET中多線程在.NET面向對象程序設計中的應用。 多線程
讀前必備: 併發
本節須要瞭解Lambda表達式基礎及匿名方法和匿名委託相關知識; 性能
A. 委託 [.net 面向對象編程基礎] (20) 委託 學習
B. Lamda表達式 [.net 面向對象程序設計進階] (5) Lamda表達式(一) 建立委託 測試
1. 關於多線程spa
在介紹多線程以前,先了解一下進程。
進程:獨立運行的程序稱爲進程。(好比Windows系統後臺程序,也能夠稱爲後臺進程)
線程:對於同一個程序分爲多個執行流,稱爲線程。
多線程:使用多個線程進行多任務處理,稱爲多線程。
2. 如何合理使用多線程?
A.對於用戶等待程序處理時,可使用多線程處理耗時任務;
B.對於一些不須要即時完成的任務,可使用後臺任務線程處理;
C.對於多併發任務,可使用多線程同時處理;
D.對於通信類,好比對線程阻塞,可使用多線程。
除過上面的幾個經常使用的狀況,還有不少狀況下可使用多線程。
3. 多線程的缺點
線程天然也有缺點,如下列出了一些:
A.若是有大量的線程,會影響性能,由於操做系統須要在他們之間切換;
B.更多的線程須要更多的內存空間;
C.線程會給程序帶來更多的bug,所以要當心使用,好比:線程任務在執行完成後,要及時釋放內存;
D.線程的停止須要考慮其對程序運行的影響。
4. .NET中的兩種多線程
.NET自己就是一個多線程的的環境。
在.NET中有兩種多線程的:
一種是使用Thread類進行線程的建立、啓動,終止等操做。
一種是使用ThreadPool類用於管理線程池.
5 .NET中使用Thread進行多線程處理
5.1 Thread類經常使用方法
.NET基礎類庫的System.Threading命名空間提供了大量的類和接口支持多線程。System.Threading.Thread類是建立並控制線程,設置其優先級並獲取其狀態最爲經常使用的類。
下面是該類幾個相當重要的方法:
Thread.Start():啓動線程的執行;
Thread.Suspend():掛起線程,或者若是線程已掛起,則不起做用;
Thread.Resume():繼續已掛起的線程;
Thread.Interrupt():停止處於Wait或者Sleep或者Join線程狀態的線程;
Thread.Join():阻塞調用線程,直到某個線程終止時爲止
Thread.Sleep():將當前線程阻塞指定的毫秒數;
Thread.Abort():以開始終止此線程的過程。若是線程已經在終止,則不能經過Thread.Start()來啓動線程。
下面是一個簡單的線程示例:
先建立一個方法:
//簡單線程方法 static void MyThreadStart() { Console.WriteLine("我是一個簡單線程"); }
建立線程調用方法:
//簡單的線程 Thread myThread = new Thread(MyThreadStart); myThread.Start();
運行結果以下:
5.2 Thread類經常使用屬性
Thread的屬性有不少,咱們先看最經常使用的幾個:
CurrentThread :用於獲取當前線程;
ThreadState 當前線程的狀態(5.4介紹);
Name:獲取或設置線程名稱;
Priority:獲取或設置線程的優先級(5.5介紹)
ManagedThreadId:獲取當前線程的惟一標識
IsBackground:獲取或設置線程是前臺線程仍是後臺線程(5.6介紹)
IsThreadPoolThread:獲取當前線程是不是託管線程池(後面章節會介紹)
下面建立一個線程示例,來講明這幾個屬性:
Thread myThreadTest = new Thread(() => { Thread.Sleep(1000); Thread t = Thread.CurrentThread; Console.WriteLine("Name: " + t.Name); Console.WriteLine("ManagedThreadId: " + t.ManagedThreadId); Console.WriteLine("State: " + t.ThreadState); Console.WriteLine("Priority: " + t.Priority); Console.WriteLine("IsBackground: " + t.IsBackground); Console.WriteLine("IsThreadPoolThread: " + t.IsThreadPoolThread); }) { Name = "線程測試", Priority = ThreadPriority.Highest }; myThreadTest.Start(); Console.WriteLine("關聯進程的運行的線程數量:"+System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
運行結果以下:
5.3 帶參數的線程方法
首先咱們使用Lambda表達式來改寫前面「簡單線程」中無參數的方法,以下:
//線程一 new Thread(()=>{ for (int i = 0; i < 5; i++) Console.WriteLine("個人線程一-[{0}]", i); }).Start();
運行結果以下:
上面示例建立的線程並無帶參數,若是是一個有參數的方法,線程該如何建立?
別擔憂,.NET爲咱們提供了一個ParameterizedThreadStart委託來解決帶一個參數的問題,以下:
//線程二 new Thread((num) =>{ for (int i = 0; i < (int)num; i++) Console.WriteLine("個人線程二--[{0}]", i); }).Start(5);
運行結果以下:
那麼問題來了,ParameterizedThreadStart委託只有一個包含數據的參數,對於多個參數呢?咱們可使用一個無參數的方法來包裝它,以下:
先建立一個帶參數的方法:
static void myThreadStart(int numA, int numB) { for (int i = (int)numA; i < (int)numB; i++) Console.WriteLine("個人線程三---[{0}]", i); }
而後經過無參數的委託來包裝它,以下:
//線程三 new Thread(() =>myThreadStart(0,5)).Start();
運行結果以下:
5.4 Thread狀態
咱們對於線程啓動之後,如何進行掛起和終止、從新啓用,首先線程在運行後有一個狀態。
System.Threading.Thread.ThreadState屬性定義了執行時線程的狀態。線程從建立到線程終止,它必定處於其中某一個狀態。
A.Unstarted:當線程被建立時,它處在Unstarted狀態。
B.Running:Thread類的Start() 方法將使線程狀態變爲Running狀態,線程將一直處於這樣的狀態,除非咱們調用了相應的方法使其掛起、阻塞、銷燬或者天然終止。
C.Suspended:若是線程被掛起,它將處於Suspended狀態。
D.Running:咱們調用resume()方法使其從新執行,這時候線程將從新變爲Running狀態。一
E.Stopped:旦線程被銷燬或者終止,線程處於Stopped狀態。處於這個狀態的線程將不復存在,正如線程開始啓動,線程將不可能回到Unstarted狀態。
F.Background:線程還有一個Background狀態,它代表線程運行在前臺仍是後臺。在一個肯定的時間,線程可能處於多個狀態。
G.WaitSleepJoin、AbortRequested:舉例子來講,一個線程被調用了Sleep而處於阻塞,而接着另一個線程調用Abort方法於這個阻塞的線程,這時候線程將同時處於WaitSleepJoin和AbortRequested狀態。
H.一旦線程響應轉爲Sle阻塞或者停止,當銷燬時會拋出ThreadAbortException異常。
ThreadState枚舉的10種執行狀態以下:
對於線程阻塞和同步問題,將在下一節繼續介紹。
5.5. 線程優先級
對於多線程任務,咱們能夠根據其重要性和運行所須要的資源狀況,設置他的優先級
System.Threading.ThreadPriority枚舉了線程的優先級別,從而決定了線程可以獲得多少CPU時間。
高優先級的線程一般會比通常優先級的線程獲得更多的CPU時間,若是不止一個高優先級的線程,操做系統將在這些線程之間循環分配CPU時間。
低優先級的線程獲得的CPU時間相對較少,當這裏沒有高優先級的線程,操做系統將挑選下一個低優先級的線程執行。
一旦低優先級的線程在執行時遇到了高優先級的線程,它將讓出CPU給高優先級的線程。
新建立的線程優先級爲通常優先級,咱們能夠設置線程的優先級別的值,以下面所示:
對於線程的優先級咱們下面作一個實驗,開啓兩個線程(一個設置高優先級,另外一個設置低優先級)。
分別委託兩個方法進行累加,看一下最終結果,代碼以下:
int numberA = 0, numberB = 0; bool state = true; new Thread(() => { while (state)numberA++; }) { Priority = ThreadPriority.Highest, Name="線程A" }.Start(); new Thread(() => { while (state)numberB++; }) { Priority = ThreadPriority.Lowest , Name="線程B" }.Start(); //讓主線程掛件1秒 Thread.Sleep(1000); state = false; Console.WriteLine("線程A: {0}, 線程B: {1}", numberA, numberB);
運行結果以下:
.NET根據優先級分配了資源,能夠看到優先級較高的線程執行的機會較大,但優先級小的線程仍然有較多的機會執行。
5.6 前臺線程和後臺線程
線程有兩種,默認狀況下爲前臺線程,要想設置爲後臺線程也很是容易,只須要加一個屬性:thread.IsBackground = true;就能夠變爲一個後臺線程了。
重點來了,先後臺線程的區別:
A.前臺線程:應用程序必須執行完全部的前臺線程才能退出;
B.後臺線程:應用程序沒必要考慮其是否所有完成,能夠直接退出。應用程序退出時,自動終止後臺線程。
下面咱們使用一個輸出從0到1000的數字,來實驗一下前臺線程和後臺線程的區別:
Thread myThread = new Thread(() =>{for (int i = 0; i < 1000; i++)Console.WriteLine(i);}); var key = Console.ReadLine(); if (key == "1") { myThread.IsBackground = true; myThread.Start(); } else { myThread.IsBackground = false; myThread.Start(); }
當咱們在控制檯等級輸入的時候,
若是輸入1(後臺線程),線程會很快關閉,並不會等輸出完1000個數字再關閉;
若是輸入其它,回車後,則線程會等1000個數字輸出完後,窗口關閉;
6. 本節要點:
A.本節主要介紹了線程的基本知識;
B.Thread經常使用的屬性、方法;
C.Thread委託的方法有多個參數的用法;
D.Thread的優先級;
E.Thread的執行狀態;
F.前臺線程和後臺線程;
後面會繼續深刻介紹利用線程提升程序性能。
==============================================================================================
<若是對你有幫助,記得點一下推薦哦,若有有不明白或錯誤之處,請多交流>
<對本系列文章閱讀有困難的朋友,請先看《.net 面向對象編程基礎》>
<轉載聲明:技術須要共享精神,歡迎轉載本博客中的文章,但請註明版權及URL>
==============================================================================================