<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    302班

    java突擊隊(duì)
    posts - 151, comments - 74, trackbacks - 0, articles - 14
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    淺析.Net下的多線程編程

    Posted on 2007-09-27 21:09 停留的風(fēng) 閱讀(278) 評(píng)論(0)  編輯  收藏 所屬分類: .NET技巧特輯
    多線程是許多操作系統(tǒng)所具有的特性,它能大大提高程序的運(yùn)行效率,所以多線程編程技術(shù)為編程者廣泛關(guān)注。目前微軟的.Net戰(zhàn)略正進(jìn)一步推進(jìn),各種相關(guān)的技術(shù)正為廣大編程者所接受,同樣在.Net中多線程編程技術(shù)具有相當(dāng)重要的地位。本文我就向大家介紹在.Net下進(jìn)行多線程編程的基本方法和步驟。 

      開始新線程 
       
      在.Net下創(chuàng)建一個(gè)新線程是非常容易的,你可以通過以下的語句來開始一個(gè)新的線程: 
         
      Thread thread = new Thread (new ThreadStart (ThreadFunc));  
      thread.Start (); 
          
      第一條語句創(chuàng)建一個(gè)新的Thread對(duì)象,并指明了一個(gè)該線程的方法。當(dāng)新的線程開始時(shí),該方法也就被調(diào)用執(zhí)行了。該線程對(duì)象通過一個(gè)System..Threading.ThreadStart類的一個(gè)實(shí)例以類型安全的方法來調(diào)用它要調(diào)用的線程方法。 
          
      第二條語句正式開始該新線程,一旦方法Start()被調(diào)用,該線程就保持在一個(gè)"alive"的狀態(tài)下了,你可以通過讀取它的IsAlive屬性來判斷它是否處于"alive"狀態(tài)。下面的語句顯示了如果一個(gè)線程處于"alive"狀態(tài)下就將該線程掛起的方法: 
          
      if (thread.IsAlive) {    
      thread.Suspend ();   
      } 

      不過請(qǐng)注意,線程對(duì)象的Start()方法只是啟動(dòng)了該線程,而并不保證其線程方法ThreadFunc()能立即得到執(zhí)行。它只是保證該線程對(duì)象能被分配到CPU時(shí)間,而實(shí)際的執(zhí)行還要由操作系統(tǒng)根據(jù)處理器時(shí)間來決定。 
       
      一個(gè)線程的方法不包含任何參數(shù),同時(shí)也不返回任何值。它的命名規(guī)則和一般函數(shù)的命名規(guī)則相同。它既可以是靜態(tài)的(static)也可以是非靜態(tài)的(nonstatic)。當(dāng)它執(zhí)行完畢后,相應(yīng)的線程也就結(jié)束了,其線程對(duì)象的IsAlive屬性也就被置為false了。下面是一個(gè)線程方法的實(shí)例: 

      public static void ThreadFunc() 
       
      { 
       
      for (int i = 0; i <10; i++) { 
       
      Console.WriteLine("ThreadFunc {0}", i); 
       
      } 
       
      } 
       
      前臺(tái)線程和后臺(tái)線程 

      .Net的公用語言運(yùn)行時(shí)(Common Language Runtime,CLR)能區(qū)分兩種不同類型的線程:前臺(tái)線程和后臺(tái)線程。這兩者的區(qū)別就是:應(yīng)用程序必須運(yùn)行完所有的前臺(tái)線程才可以退出;而對(duì)于后臺(tái)線程,應(yīng)用程序則可以不考慮其是否已經(jīng)運(yùn)行完畢而直接退出,所有的后臺(tái)線程在應(yīng)用程序退出時(shí)都會(huì)自動(dòng)結(jié)束。 

      一個(gè)線程是前臺(tái)線程還是后臺(tái)線程可由它的IsBackground屬性來決定。這個(gè)屬性是可讀又可寫的。它的默認(rèn)值為false,即意味著一個(gè)線程默認(rèn)為前臺(tái)線程。我們可以將它的IsBackground屬性設(shè)置為true,從而使之成為一個(gè)后臺(tái)線程。 

      下面的例子是一個(gè)控制臺(tái)程序,程序一開始便啟動(dòng)了10個(gè)線程,每個(gè)線程運(yùn)行5秒鐘時(shí)間。由于線程的IsBackground屬性默認(rèn)為false,即它們都是前臺(tái)線程,所以盡管程序的主線程很快就運(yùn)行結(jié)束了,但程序要到所有已啟動(dòng)的線程都運(yùn)行完畢才會(huì)結(jié)束。示例代碼如下: 

      using System; 
       
      using System.Threading; 
       
      class MyApp 
       
      { 
       
      public static void Main () 
       
      { 
       
      for (int i=0; i<10; i++) { 
       
      Thread thread = new Thread (new ThreadStart (ThreadFunc)); 
       
      thread.Start (); 
       
      } 
       
      } 
       
      private static void ThreadFunc () 
       
      { 
       
      DateTime start = DateTime.Now; 
       
      while ((DateTime.Now - start).Seconds <5) 
       
      ; 
       
      } 
       
      } 
       

    接下來我們對(duì)上面的代碼進(jìn)行略微修改,將每個(gè)線程的IsBackground屬性都設(shè)置為true,則每個(gè)線程都是后臺(tái)線程了。那么只要程序的主線程結(jié)束了,整個(gè)程序也就結(jié)束了。示例代碼如下: 
      using System; 
       
      using System.Threading; 
       
      class MyApp 
       
      { 
       
      public static void Main () 
       
      { 
       
      for (int i=0; i<10; i++) { 
       
      Thread thread = new Thread (new ThreadStart (ThreadFunc)); 
       
      thread.IsBackground = true; 
       
      thread.Start (); 
       
      } 
       
      } 
       
      private static void ThreadFunc () 
       
      { 
       
      DateTime start = DateTime.Now; 
       
      while ((DateTime.Now - start).Seconds <5) 
       
      ; 
       
      }  
      } 

      既然前臺(tái)線程和后臺(tái)線程有這種差別,那么我們?cè)趺粗涝撊绾卧O(shè)置一個(gè)線程的IsBackground屬性呢?下面是一些基本的原則:對(duì)于一些在后臺(tái)運(yùn)行的線程,當(dāng)程序結(jié)束時(shí)這些線程沒有必要繼續(xù)運(yùn)行了,那么這些線程就應(yīng)該設(shè)置為后臺(tái)線程。比如一個(gè)程序啟動(dòng)了一個(gè)進(jìn)行大量運(yùn)算的線程,可是只要程序一旦結(jié)束,那個(gè)線程就失去了繼續(xù)存在的意義,那么那個(gè)線程就該是作為后臺(tái)線程的。而對(duì)于一些服務(wù)于用戶界面的線程往往是要設(shè)置為前臺(tái)線程的,因?yàn)榧词钩绦虻闹骶€程結(jié)束了,其他的用戶界面的線程很可能要繼續(xù)存在來顯示相關(guān)的信息,所以不能立即終止它們。這里我只是給出了一些原則,具體到實(shí)際的運(yùn)用往往需要編程者的進(jìn)一步仔細(xì)斟酌。 

      線程優(yōu)先級(jí) 

      一旦一個(gè)線程開始運(yùn)行,線程調(diào)度程序就可以控制其所獲得的CPU時(shí)間。如果一個(gè)托管的應(yīng)用程序運(yùn)行在Windows機(jī)器上,則線程調(diào)度程序是由Windows所提供的。在其他的平臺(tái)上,線程調(diào)度程序可能是操作系統(tǒng)的一部分,也自然可能是.Net框架的一部分。不過我們這里不必考慮線程的調(diào)度程序是如何產(chǎn)生的,我們只要知道通過設(shè)置線程的優(yōu)先級(jí)我們就可以使該線程獲得不同的CPU時(shí)間。 

      線程的優(yōu)先級(jí)是由Thread.Priority屬性控制的,其值包含:ThreadPriority.Highest、ThreadPriority.AboveNormal、ThreadPriority.Normal、ThreadPriority.BelowNormal和ThreadPriority.Lowest。從它們的名稱上我們自然可以知道它們的優(yōu)先程度,所以這里就不多作介紹了。 
       
      線程的默認(rèn)優(yōu)先級(jí)為ThreadPriority.Normal。理論上,具有相同優(yōu)先級(jí)的線程會(huì)獲得相同的CPU時(shí)間,不過在實(shí)際執(zhí)行時(shí),消息隊(duì)列中的線程阻塞或是操作系統(tǒng)的優(yōu)先級(jí)的提高等原因會(huì)導(dǎo)致具有相同優(yōu)先級(jí)的線程會(huì)獲得不同的CPU時(shí)間。不過從總體上來考慮仍可以忽略這種差異。你可以通過以下的方法來改變一個(gè)線程的優(yōu)先級(jí)。 

      thread.Priority = ThreadPriority.AboveNormal; 

      或是: 

      thread.Priority = ThreadPriority.BelowNormal; 

      通過上面的第一句語句你可以提高一個(gè)線程的優(yōu)先級(jí),那么該線程就會(huì)相應(yīng)的獲得更多的CPU時(shí)間;通過第二句語句你便降低了那個(gè)線程的優(yōu)先級(jí),于是它就會(huì)被分配到比原來少的CPU時(shí)間了。你可以在一個(gè)線程開始運(yùn)行前或是在它的運(yùn)行過程中的任何時(shí)候改變它的優(yōu)先級(jí)。理論上你還可以任意的設(shè)置每個(gè)線程的優(yōu)先級(jí),不過一個(gè)優(yōu)先級(jí)過高的線程往往會(huì)影響到其他線程的運(yùn)行,甚至影響到其他程序的運(yùn)行,所以最好不要隨意的設(shè)置線程的優(yōu)先級(jí)。  
       
      掛起線程和重新開始線程 

      Thread類分別提供了兩個(gè)方法來掛起線程和重新開始線程,也就是Thread.Suspend能暫停一個(gè)正在運(yùn)行的線程,而Thread.Resume又能讓那個(gè)線程繼續(xù)運(yùn)行。不像Windows內(nèi)核,.Net框架是不記錄線程的掛起次數(shù)的,所以不管你掛起線程過幾次,只要一次調(diào)用Thread.Resume就可以讓掛起的線程重新開始運(yùn)行。 

      Thread類還提供了一個(gè)靜態(tài)的Thread.Sleep方法,它能使一個(gè)線程自動(dòng)的掛起一定的時(shí)間,然后自動(dòng)的重新開始。一個(gè)線程能在它自身內(nèi)部調(diào)用Thread.Sleep方法,也能在自身內(nèi)部調(diào)用Thread.Suspend方法,可是一定要?jiǎng)e的線程來調(diào)用它的Thread.Resume方法才可以重新開始。這一點(diǎn)是不是很容易想通的啊?下面的例子顯示了如何運(yùn)用Thread.Sleep方法: 

      while (ContinueDrawing) {   
      DrawNextSlide ();  
      Thread.Sleep (5000);  
      } 

      終止線程 
       在托管的代碼中,你可以通過以下的語句在一個(gè)線程中將另一個(gè)線程終止掉: 
      thread.Abort (); 
      下面我們來解釋一下Abort()方法是如何工作的。因?yàn)楣谜Z言運(yùn)行時(shí)管理了所有的托管的線程,同樣它能在每個(gè)線程內(nèi)拋出異常。Abort()方法能在目標(biāo)線程中拋出一個(gè)ThreadAbortException異常從而導(dǎo)致目標(biāo)線程的終止。不過Abort()方法被調(diào)用后,目標(biāo)線程可能并不是馬上就終止了。因?yàn)橹灰繕?biāo)線程正在調(diào)用非托管的代碼而且還沒有返回的話,該線程就不會(huì)立即終止。而如果目標(biāo)線程在調(diào)用非托管的代碼而且陷入了一個(gè)死循環(huán)的話,該目標(biāo)線程就根本不會(huì)終止。不過這種情況只是一些特例,更多的情況是目標(biāo)線程在調(diào)用托管的代碼,一旦Abort()被調(diào)用那么該線程就立即終止了。 

      在實(shí)際應(yīng)用中,一個(gè)線程終止了另一個(gè)線程,不過往往要等那個(gè)線程完全終止了它才可以繼續(xù)運(yùn)行,這樣的話我們就應(yīng)該用到它的Join()方法。示例代碼如下: 

      thread.Abort (); // 要求終止另一個(gè)線程   
      thread.Join (); // 只到另一個(gè)線程完全終止了,它才繼續(xù)運(yùn)行 

      但是如果另一個(gè)線程一直不能終止的話(原因如前所述),我們就需要給Join()方法設(shè)置一個(gè)時(shí)間限制,方法如下: 

      thread.Join (5000); // 暫停5秒 
      
      這樣,在5秒后,不管那個(gè)線程有沒有完全終止,本線程就強(qiáng)行運(yùn)行了。該方法還返回一個(gè)布爾型的值,如果是true則表明那個(gè)線程已經(jīng)完全終止了,而如果是false的話,則表明已經(jīng)超過了時(shí)間限制了。 
       
      時(shí)鐘線程 
      
      .Net框架中的Timer類可以讓你使用時(shí)鐘線程,它是包含在System.Threading名字空間中的,它的作用就是在一定的時(shí)間間隔后調(diào)用一個(gè)線程的方法。下面我給大家展示一個(gè)具體的實(shí)例,該實(shí)例以1秒為時(shí)間間隔,在控制臺(tái)中輸出不同的字符串,代碼如下: 
      
      using System;  
      using System.Threading;  
      class MyApp  
      { 
      private static bool TickNext = true;  
      public static void Main ()  
      {  
      Console.WriteLine ("Press Enter to terminate...");  
      TimerCallback callback = new TimerCallback (TickTock);  
      Timer timer = new Timer (callback, null, 1000, 1000);   
      Console.ReadLine ();   
      }   
      private static void TickTock (object state)    
      {   
      Console.WriteLine (TickNext ? "Tick" : "Tock");   
      TickNext = ! TickNext;    
      }    
      }  
      從上面的代碼中,我們知道第一個(gè)函數(shù)回調(diào)是在1000毫秒后才發(fā)生的,以后的函數(shù)回調(diào)也是在每隔1000毫秒之后發(fā)生的,這是由Timer對(duì)象的構(gòu)造函數(shù)中的第三個(gè)參數(shù)所決定的。程序會(huì)在1000毫秒的時(shí)間間隔后不斷的產(chǎn)生新線程,只到用戶輸入回車才結(jié)束運(yùn)行。不過值得注意的是,雖然我們?cè)O(shè)置了時(shí)間間隔為1000毫秒,但是實(shí)際運(yùn)行的時(shí)候往往并不能非常精確。因?yàn)閃indows操作系統(tǒng)并不是一個(gè)實(shí)時(shí)系統(tǒng),而公用語言運(yùn)行時(shí)也不是實(shí)時(shí)的,所以由于線程調(diào)度的千變?nèi)f化,實(shí)際的運(yùn)行效果往往是不能精確到毫秒級(jí)的,但是對(duì)于一般的應(yīng)用來說那已經(jīng)是足夠的了,所以你也不必十分苛求。 

      小結(jié)  
      本文介紹了在.Net下進(jìn)行多線程編程所需要掌握的一些基本知識(shí)。從文章中我們可以知道在.Net下進(jìn)行多線程編程相對(duì)以前是有了大大的簡化,但是其功能并沒有被削弱。使用以上的一些基本知識(shí),讀者就可以試著編寫.Net下的多線程程序了。不過要編寫出功能更加強(qiáng)大而且Bug少的多線程應(yīng)用程序,讀者需要掌握諸如線程同步、線程池等高級(jí)的多線程編程技術(shù)。讀者不妨參考一些操作系統(tǒng)方面或是多線程編程方面的技術(shù)叢書。
    主站蜘蛛池模板: 亚洲免费福利视频| 国产一区二区三区在线观看免费| 久久亚洲精品成人无码网站| 人妻视频一区二区三区免费| 看一级毛片免费观看视频| 亚洲av永久无码制服河南实里| 成年午夜视频免费观看视频| 国产裸体美女永久免费无遮挡| 亚洲精品视频久久| 亚洲国产成人精品91久久久| 黄在线观看www免费看| 亚洲老熟女五十路老熟女bbw | 亚洲人妖女同在线播放| 亚洲av无码不卡私人影院| 99热免费在线观看| 一区免费在线观看| 免费人成在线观看播放国产| 182tv免费观看在线视频| 免费一级毛片在线播放放视频| 亚洲美女高清一区二区三区| 深夜免费在线视频| 久久精品国产亚洲av麻豆图片 | 69av免费视频| 久久国产精品免费一区二区三区| 亚洲欧洲另类春色校园网站| 免费电影在线观看网站| 人人玩人人添人人澡免费| 免费看一级毛片在线观看精品视频| 亚洲成AV人片久久| 好男人视频在线观看免费看片 | 91免费在线播放| 老司机精品免费视频| 精品亚洲国产成人av| 亚洲伊人久久大香线蕉啊| 亚洲av日韩av不卡在线观看| 免费一级毛片正在播放| 久久天天躁狠狠躁夜夜免费观看| 国产精品免费大片| 在线观看肉片AV网站免费| 亚洲激情电影在线| 久久精品国产69国产精品亚洲|