1. 程式人生 > >多線程學習系列二(使用System.Threading)

多線程學習系列二(使用System.Threading)

設定 進行 運行時 art lowest 模擬 state 執行 png

一、什麽是System.Threading.Thread?如何使用System.Threading.Thread進行異步操作

System.Threading.Thread:操作系統實現線程並提供各種非托管API來創建和管理線程,CLR封裝這些非托管線程,在托管代碼中通過System.Threading.Thread類來公開它們。

簡單說就是System.Threading.Thread是一個創建和管理線程的類。

如何使用它來進行異步操作

public class Test

    {

        public static int Index = 1000;

        
public static void Main() { //將DoWork方法設定為在Thread上執行的方法 ThreadStart threadStart = DoWork; //初始化Thread實例 Thread thread = new Thread(threadStart); //開啟任務 thread.Start(); for (int i = 0; i < Index; i++) { Console.Write(
"-"); } thread.Join(); Console.ReadLine(); } public static void DoWork () { for (int i = 0; i < Index; i++) { Console.Write("+"); } } }

  技術分享圖片

技術分享圖片技術分享圖片

  最開始Thread創建的新線程與Main函數的主線程輪流執行,相互切換。而不是先執行DoWork的輸出+再執行後面的輸出-,兩個線程相互獨立的,不會等待對方的執行。直到thread.Join()方法阻塞調用線程,直到thread實例的線程終止才執行其他的線程,這樣就是一直執行完+,最後執行-

二、線程的管理

線程包含了大量的方法和屬性,用於它們的執行。我們就來看一些常用的基本的方法和屬性吧:

Join()。阻塞調用線程,直至此實例表示的線程終止,Join()方法的重載運行獲得一個int或者TimeSpan作為參數,意思是指定最多等待Thread執行的時間,過期不候

IsBackGround。新線程默認為“前臺”線程,操作系統將在進程中所有前臺線程完成後終止進程。可以將thread.IsBackGround設置為True,這樣就標記此線程為後臺線程,這樣後臺線程任在進行,前臺進程也允許終止。不過最好不要半路中止任何線程,最好是在線程退出之前顯示的退出每一個線程。
Prioriy每個線程關聯優先級的,這個屬性就是設置線程的優先級(thread.Priority = ThreadPriority.Highest;(Lowest、BelowNormal、Normal、AboveNormal、Highest)),註意使用,避免造成“饑餓”的情況,一個高優先級的線程運行,其他低優先級的線程眼睜睜的看著

ThreadState。如果只是想要知道一個線程是否在運行或者是否已經完成了所有的工作的話,可以使用IsAlive。當然更全面的獲得線程的詳細的信息還是需要通過使用ThreadState來獲取。

三、在生產代碼中不要要線程進入睡眠

靜態方法Thread.Sleep(),可以使當前方法進入睡眠—也就是告訴操作系統在指定的時間內不要為該線程調度任何的時間片。正如書中所說,這個設計表面看著合理,但是好好想下會發現有點不妥:

1、 操作系統不保證計時器的精確性,設置休眠100毫秒,操作系統會保證最少休眠100毫秒,但不一定就精確到100毫秒,可能時間會更長

2、 Thread.Sleep()經常被稱為“窮人的同步系統”,意味著先把這個線程休眠,等當前異步工作完成。指望當線程休眠結束後當前異步工作也會完成,這並不是一個好的想法,因為異步操作花費的時間可能超出你的想象

3、 線程休眠不是一個好的編程實踐,花費了昂貴的資源開啟線程,但是卻要它休眠,就好比花了大價錢雇了工人,然後要他去睡覺一樣的。

當然有它的存在肯定會有其意義,其中一點:就是將線程的休眠的時間設置0,相當於告訴操作系統:“當前線程的時間片就送給其他的線程了。”然後,該線程會被正常調度,不會發生更多的延遲。其次Thread.Sleep()也可模擬高延遲的操作進行測試。

四、在生產代碼中不要中止線程

Tread對象中Abort()方法一旦執行就是嘗試銷毀線程,會造成“運行時”在線程中引發異常,最好不要中止線程:

1、 該方法只是嘗試銷毀線程,不保證一定是成功的。

2、 中止線程時可能正處在lock代碼塊中,lock阻止不了異常,會導致中斷,從而lock鎖會自動釋放。執行到一半的關鍵代碼從而中斷。違背了lock的原意,lock原意就是確保關鍵代碼塊的安全並防止其他線程進入的。

3、 線程終止時CLR保證自己內部的數據結構不會被破壞,但是BCL沒有保證,所以中止線程可能導致數據結構或者BCL中的數據結構被破壞

五、線程池的處理

BCL提供的線程池可以使開發人員不是直接分配線程了,而是告訴線程池想要完成什麽樣的工作,工作結束後線程不是被銷毀而是會回到線程池中,這樣就節省了創建線程以及銷毀線程所需要的開銷。

在線程池中我們需要註意到的是:

1、要使用線程池向處理器受限任務高效的分配處理器的時間

2、避免把池中的工作者線程分配給I/O受限或者長時間運行的任務,如果需要可以考慮使用TPL,因為長時間的任務會造成工作的排隊,那些排隊的工作必定會受到延遲的。

多線程學習系列二(使用System.Threading)