C#多線程 線程的啓動

在實例化Thread的實例,須要提供一個委託,在實例化這個委託時所用到的參數是線程未來啓動時要運行的方法。在.net中提供了兩種啓動線程的方式,一種是不帶參數的啓動方式,另外一種是帶參數的啓動的方式。

不帶參數的啓動方式

若是啓動參數時無需其它額外的信息,能夠使用ThreadStart來實例化Thread,以下面的代碼:數組

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Threading;
 5 
 6 namespace ConsoleApplication_Thread
 7 {
 8     class Program
 9     {
10         int interval = 200;
11         static void Main(string[] args)
12         {
13             Program p = new Program();
14             Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun));
15             //Thread nonParameterThread = new Thread(p.NonParameterRun);
16             nonParameterThread.Start();
17         }
18 
19         /// <summary>
20         ///  不帶參數的啓動方法
21         /// </summary>
22         public void NonParameterRun()
23         {
24             for (int i = 0; i < 10; i++)
25             {
26                 Console.WriteLine("系統當前時間毫秒值:"+DateTime.Now.Millisecond.ToString());
27                 Thread.Sleep(interval);
28             }
29             Console.ReadKey();
30         }
31     }
32 }

程序的運行效果咱們不用運行也會知道,那就是在循環中將系統當前時間的毫秒部分輸出出來,在每次輸出以後會將當前線程暫停一下,直到10次以後運行完畢,終止線程的執行。函數

 

在上面的代碼中咱們是經過定義全局變量的方法來指定線程暫停間隔,按照這種方法,假如要運行10個線程,每一個線程的暫停間隔不同的話,就須要定義10個全局變量,雖然最終不影響系統的運行效果,可是總以爲不是太爽。有沒有比較簡單一點的辦法呢?有!那就是使用帶參數的啓動方法。oop

 

帶參數的啓動方法

若是要在實例化線程時要帶一些參數,就不能用ThreadStart委託做爲構造函數的參數來實例化Thread了,而要 ParameterizedThreadStart委託,和ThreadStart同樣的是它也是線程啓動時要執行的方法,和ThreadStart不一樣的是,它在實例化時能夠用一個帶有一個Object參數的方法做爲構造函數的參數,而實例化ThreadStart時所用到的方法是沒有參數的。

爲何是Object這樣的參數呢?很簡單,由於在.net中Object是全部類型的基類,用它能夠表示Array(數組)、Interface(接口)、ValueType(值類型,如bool,byte,char,short,int,float,long,double等)、class(類)等.net中的類型。固然,這也意味着若是你要啓動一個線程,給它傳遞一個int類型參數時,必須在啓動方法中進行相應的類型轉換。

下面就是一個例子,在啓動線程時指定了線程的暫停間隔,代碼以下:  this

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Threading;
 5 
 6 namespace ConsoleApplication_Thread
 7 {
 8     class Program
 9     {
10         //int interval = 200;
11         static void Main(string[] args)
12         {
13             Program p = new Program();
14             Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
15             parameterThread.Name = "線程1:";//指定當前線程名稱
16             parameterThread.Start(1000);//將值1000傳遞給子線程委託方法的參數上
17         }
18 
19         /// <summary>
20         /// 帶參數的啓動方法
21         /// </summary>
22         /// <param name="ms"></param>
23         public void ParameterRun(object ms)
24         {
25             int j = 10;
26             int.TryParse(ms.ToString(), out j);//這裏採用了TryParse方法,避免不能轉換時出現異常
27 
28             for (int i = 0; i < 10; i++)
29             {
30                 Console.WriteLine(Thread.CurrentThread.Name + "系統當前時間毫秒值:" + DateTime.Now.Millisecond.ToString());
31                 Thread.Sleep(j);
32             }
33             Console.ReadLine();
34         }
35     }
36 }

在這個方法裏,咱們在啓動線程時順便指定了線程的暫停間隔,也就是這句:
parameterThread.Start(30);
線程啓動時運行的方法是public void ParameterRun(object ms),這個值爲1000的int類型變量被裝箱成object,因此在方法中還須要將它轉換成int類型,這個能夠經過拆箱或者其它辦法解決。spa

 

假如咱們要啓動兩個線程,每一個線程的暫停間隔不同,啓動代碼以下:  .net

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Threading;
 5 
 6 namespace ConsoleApplication_Thread
 7 {
 8     class Program
 9     {
10         //int interval = 200;
11         static void Main(string[] args)
12         {
13             Program p = new Program();
14             Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
15             parameterThread.Name = "Thread A:";
16             parameterThread.Start(3000);
17             //啓動第二個線程
18             parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
19             parameterThread.Name = "Thread B:";
20             parameterThread.Start(6000);
21         }
22 
23         /// <summary>
24         /// 帶參數的啓動方法
25         /// </summary>
26         /// <param name="ms">讓線程在運行過程當中的休眠間隔</param>
27         public void ParameterRun(object ms)
28         {
29             int j = 10;
30             int.TryParse(ms.ToString(), out j);//這裏採用了TryParse方法,避免不能轉換時出現異常
31             for (int i = 0; i < 10; i++)
32             {
33                 Console.WriteLine(Thread.CurrentThread.Name + "系統當前時間毫秒值:" + DateTime.Now.Millisecond.ToString());
34                 Thread.Sleep(j);//讓線程暫停
35             }
36             Console.ReadKey();
37         }
38     }
39 }

對上面的代碼作一點說明,就是線程啓動以後,線程的實例沒必要再存在(也就是說實例被銷燬了),例如在上面的代碼中我用的是同一個實例實例化了兩個線程,而且這兩個線程運行很正常。線程

 

繼續探索

上面解決了一個問題,若是在啓動線程時須要參數如何解決,若是針對上面的問題繼續發掘,好比:在啓動線程時不但要指定線程的暫停間隔,還須要指定循環次數(在上面的全部例子中都是執行10次的),說白點就是我須要不少的參數,這個問題該如何解決呢?

有兩種辦法能夠解決:

首先能夠繼續在ParameterizedThreadStart這裏作文章,由於這裏能夠使用一個Object類型的參數,那麼能夠經過數組或者一個類來解決(由於它們都是Object的子類)。我在作某個系統時確實採用數組處理過這種狀況,這樣就要求在線程啓動方法中必須清楚知道數組中每一個參數的用途,不是太方便。
這裏說說從新定義一個實體類來解決的方法,代碼以下:code

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Threading;
 5 
 6 namespace ConsoleApplication_Thread
 7 {
 8     class Program
 9     {
10         //int interval = 200;
11         static void Main(string[] args)
12         {
13             Program p = new Program();
14             Thread parameterThread = new Thread(new ParameterizedThreadStart(p.MyParameterRun));
15             parameterThread.Name = "線程 A:";
16             MyThreadParameter paramter = new MyThreadParameter(1000, 20);
17             parameterThread.Start(paramter);
18         }
19 
20 
21         /// <summary>
22         /// 帶多個參數的啓動方法
23         /// </summary>
24         /// <param name="ms">方法參數</param>
25         public void MyParameterRun(object ms)
26         {
27             MyThreadParameter parameter = ms as MyThreadParameter;//類型轉換
28             if (parameter != null)
29             {
30                 for (int i = 0; i < parameter.LoopCount; i++)
31                 {
32                     Console.WriteLine(Thread.CurrentThread.Name + "系統當前時間毫秒值:" + DateTime.Now.Millisecond.ToString());
33                     Thread.Sleep(parameter.Interval);//讓線程暫停
34                 }
35                 Console.ReadKey();
36             }
37         }
38 
39 
40     }
41     class MyThreadParameter
42     {
43         private int interval;
44         private int loopCount;
45         /// <summary>
46         /// 循環次數
47         /// </summary>
48         public int LoopCount
49         {
50             get { return loopCount; }
51         }
52 
53         /// <summary>
54         /// 線程的暫停間隔
55         /// </summary>
56         public int Interval
57         {
58             get { return interval; }
59         }
60         /// <summary>
61         /// 構造函數
62         /// </summary>
63         /// <param name="interval">線程的暫停間隔</param>
64         /// <param name="loopCount">循環次數</param>
65         public MyThreadParameter(int interval, int loopCount)
66         {
67             this.interval = interval;
68             this.loopCount = loopCount;
69         }
70     }
71 }

 

第二種方法和上面方法有些類似,也是須要引入外部類,而且將Thread實例放在引入的類中,這種狀況適合於在線程中處理的業務邏輯比較複雜的狀況。在前不久處理的一個項目中我用過這種狀況,它是用來實現雙向數據傳輸的。
如實現上面的效果,代碼以下:  blog

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Threading;
 5 
 6 namespace ConsoleApplication_Thread
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             MyThreadParameter parameterThread = new myThreadParameter(200, 50);
13             parameterThread.Start();
14         } 
15     }
16 
17 
18     class MyThreadParameter
19     {
20 
21         private int interval;
22         private int loopCount;
23         private Thread thread;
24         /// <summary>
25         /// 構造函數
26         /// </summary>
27         /// <param name="interval">線程的暫停間隔</param>
28         /// <param name="loopCount">循環次數</param>
29         public MyThreadParameter(int interval, int loopCount)
30         {
31             this.interval = interval;
32             this.loopCount = loopCount;
33             thread = new Thread(new ThreadStart(Run));
34         }
35         public void Start()
36         {
37             if (thread != null)
38             {
39                 thread.Start();
40             }
41         }
42         private void Run()
43         {
44             for (int i = 0; i < loopCount; i++)
45             {
46                 Console.WriteLine("系統當前時間毫秒值:" + DateTime.Now.Millisecond.ToString());
47                 Thread.Sleep(interval);//讓線程暫停
48             }
49         }
50     } 
51 }

上面的代碼的運行效果和前面的代碼運行效果相似,只不過是將業務處理代碼放在一個單獨的類MyThreadParameter中,使得MyThreadParameter看起來也像一個Thread,實際上維護的仍是其內部的Thread,在一些大型系統中這樣作的好處是便於維護。

總結:在本篇主要講述如何啓動線程的問題,在啓動時可能會遇到無需參數、須要多個參數的狀況,在這裏講述瞭如何解決這些問題的思路。在.net類庫中雖然存在着龐大的類庫,可是並非總會有合適的類來解決咱們所遇到的問題,可是隻要肯動腦筋總會想到合適的辦法。接口

相關文章
相關標籤/搜索