C#線程的啟動(dòng)
在實(shí)例化Thread的實(shí)例,需要提供一個(gè)委托,在實(shí)例化這個(gè)委托時(shí)所用到的參數(shù)是線程將來(lái)啟動(dòng)時(shí)要運(yùn)行的方法。在.net中提供了兩種啟動(dòng)線程的方式,一種是不帶參數(shù)的啟動(dòng)方式,另一種是帶參數(shù)的啟動(dòng)的方式。
在實(shí)例化Thread的實(shí)例,需要提供一個(gè)委托,在實(shí)例化這個(gè)委托時(shí)所用到的參數(shù)是線程將來(lái)啟動(dòng)時(shí)要運(yùn)行的方法。在.net中提供了兩種啟動(dòng)線程的方式,一種是不帶參數(shù)的啟動(dòng)方式,另一種是帶參數(shù)的啟動(dòng)的方式。
C#線程的啟動(dòng):不帶參數(shù)的啟動(dòng)方式
如果啟動(dòng)參數(shù)時(shí)無(wú)需其它額外的信息,可以使用ThreadStart來(lái)實(shí)例化Thread,如下面的代碼:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace StartThread
- {
- class Program
- {
- int interval = 200;
- static void Main(string[] args)
- {
- Program p = new Program();
- Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun));
- nonParameterThread.Start();
- }
- ///
- /// 不帶參數(shù)的啟動(dòng)方法
- ///
- public void NonParameterRun()
- {
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine("系統(tǒng)當(dāng)前時(shí)間毫秒值:"+DateTime.Now.Millisecond.ToString());
- Thread.Sleep(interval);//讓線程暫停
- }
- }
- }
程序的運(yùn)行效果我們不用運(yùn)行也會(huì)知道,那就是在循環(huán)中將系統(tǒng)當(dāng)前時(shí)間的毫秒部分輸出出來(lái),在每次輸出之后會(huì)將當(dāng)前線程暫停一下,直到10次之后運(yùn)行完畢,終止線程的執(zhí)行。
在上面的代碼中我們是通過(guò)定義全局變量的方法來(lái)指定線程暫停間隔,按照這種方法,假如要運(yùn)行10個(gè)線程,每個(gè)線程的暫停間隔不一樣的話,就需要定義10個(gè)全局變量,雖然最終不影響系統(tǒng)的運(yùn)行效果,但是總覺(jué)得不是太爽。
有沒(méi)有比較簡(jiǎn)單一點(diǎn)的辦法呢?有!那就是使用帶參數(shù)的啟動(dòng)方法。
C#線程的啟動(dòng):帶參數(shù)的啟動(dòng)方法
如果要在實(shí)例化線程時(shí)要帶一些參數(shù),就不能用ThreadStart委托作為構(gòu)造函數(shù)的參數(shù)來(lái)實(shí)例化Thread了,而要ParameterizedThreadStart委托,和ThreadStart一樣的是它也是線程啟動(dòng)時(shí)要執(zhí)行的方法,和ThreadStart不同的是,它在實(shí)例化時(shí)可以用一個(gè)帶有一個(gè)Object參數(shù)的方法作為構(gòu)造函數(shù)的參數(shù),而實(shí)例化ThreadStart時(shí)所用到的方法是沒(méi)有參數(shù)的。
為什么是Object這樣的參數(shù)呢?很簡(jiǎn)單,因?yàn)樵?net中Object是所有類型的基類,用它可以表示Array(數(shù)組)、Interface(接口)、ValueType(值類型,如bool,byte,char,short,int,float,long,double等)、class(類)等.net中的類型。當(dāng)然,這也意味著如果你要啟動(dòng)一個(gè)線程,給它傳遞一個(gè)int類型參數(shù)時(shí),必須在啟動(dòng)方法中進(jìn)行相應(yīng)的類型轉(zhuǎn)換。
下面就是一個(gè)例子,在啟動(dòng)線程時(shí)指定了線程的暫停間隔,代碼如下:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace StartThread
- {
- class Program
- {
- int interval = 200;
- static void Main(string[] args)
- {
- Program p = new Program();
- Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
- parameterThread.Name = "Thread A:";
- parameterThread.Start(30);
- }
- ///
- /// 帶參數(shù)的啟動(dòng)方法
- ///
- /// 讓線程在運(yùn)行過(guò)程中的休眠間隔
- public void ParameterRun(object ms)
- {
- int j = 10;
- int.TryParse(ms.ToString(), out j);//這里采用了TryParse方法,避免不能轉(zhuǎn)換時(shí)出現(xiàn)異常
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine(Thread.CurrentThread.Name+"系統(tǒng)當(dāng)前時(shí)間毫秒值:" + DateTime.Now.Millisecond.ToString());
- Thread.Sleep(j);//讓線程暫停
- }
- }
- }
- }
在這個(gè)方法里,我們?cè)趩?dòng)線程時(shí)順便指定了線程的暫停間隔,也就是這句:
- parameterThread.Start(30);
線程啟動(dòng)時(shí)運(yùn)行的方法是public void ParameterRun(object ms),這個(gè)值為30的int類型變量被裝箱成object,所以在方法中還需要將它轉(zhuǎn)換成int類型,這個(gè)可以通過(guò)拆箱或者其它辦法解決。
假如我們要啟動(dòng)兩個(gè)線程,每個(gè)線程的暫停間隔不一樣,啟動(dòng)代碼如下:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace StartThread
- {
- class Program
- {
- int interval = 200;
- static void Main(string[] args)
- {
- Program p = new Program();
- Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
- parameterThread.Name = "Thread A:";
- parameterThread.Start(30);
- //啟動(dòng)第二個(gè)線程
- parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun));
- parameterThread.Name = "Thread B:";
- parameterThread.Start(60);
- }
- ///
- /// 帶參數(shù)的啟動(dòng)方法
- ///
- /// 讓線程在運(yùn)行過(guò)程中的休眠間隔
- public void ParameterRun(object ms)
- {
- int j = 10;
- int.TryParse(ms.ToString(), out j);//這里采用了TryParse方法,避免不能轉(zhuǎn)換時(shí)出現(xiàn)異常
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine(Thread.CurrentThread.Name+"系統(tǒng)當(dāng)前時(shí)間毫秒值:" + DateTime.Now.Millisecond.ToString());
- Thread.Sleep(j);//讓線程暫停
- }
- }
- }
- }
對(duì)上面的代碼做一點(diǎn)說(shuō)明,就是線程啟動(dòng)之后,線程的實(shí)例不必再存在,例如在上面的代碼中我用的是同一個(gè)實(shí)例實(shí)例化了兩個(gè)線程,并且這兩個(gè)線程運(yùn)行很正常。
C#線程的啟動(dòng):繼續(xù)探索
上面解決了一個(gè)問(wèn)題,如果在啟動(dòng)線程時(shí)需要參數(shù)如何解決,如果針對(duì)上面的問(wèn)題繼續(xù)發(fā)掘,比如:在啟動(dòng)線程時(shí)不但要指定線程的暫停間隔,還需要指定循環(huán)次數(shù)(在上面的所有例子中都是執(zhí)行10次的),這個(gè)問(wèn)題該如何解決呢?
有兩種辦法可以解決:
首先可以繼續(xù)在ParameterizedThreadStart這里做文章,因?yàn)檫@里可以使用一個(gè)Object類型的參數(shù),那么可以通過(guò)數(shù)組或者一個(gè)類來(lái)解決(因?yàn)樗鼈兌际荗bject的子類)。我在做某個(gè)系統(tǒng)時(shí)確實(shí)采用數(shù)組處理過(guò)這種情況,這樣就要求在線程啟動(dòng)方法中必須清楚知道數(shù)組中每個(gè)參數(shù)的用途,不是太方便。
這里說(shuō)說(shuō)重新定義一個(gè)實(shí)體類來(lái)解決的方法,代碼如下。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace StartThread
- {
- class MyThreadParameter
- {
- private int interval;
- private int loopCount;
- ///
- /// 循環(huán)次數(shù)
- ///
- public int LoopCount
- {
- get { return loopCount; }
- }
- ///
- /// 線程的暫停間隔
- ///
- public int Interval
- {
- get { return interval; }
- }
- ///
- /// 構(gòu)造函數(shù)
- ///
- /// 線程的暫停間隔
- /// 循環(huán)次數(shù)
- public MyThreadParameter(int interval,int loopCount)
- {
- this.interval = interval;
- this.loopCount = loopCount;
- }
- }
- class Program
- {
- int interval = 200;
- static void Main(string[] args)
- {
- Program p = new Program();
- Thread parameterThread = new Thread(new ParameterizedThreadStart(p.MyParameterRun));
- parameterThread.Name = "Thread A:";
- MyThreadParameter paramter = new MyThreadParameter(50, 20);
- parameterThread.Start(paramter);
- }
- ///
- /// 帶多個(gè)參數(shù)的啟動(dòng)方法
- ///
- /// 方法參數(shù)
- public void MyParameterRun(object ms)
- {
- MyThreadParameter parameter = ms as MyThreadParameter;//類型轉(zhuǎn)換
- if (parameter != null)
- {
- for (int i = 0; i < parameter.LoopCount; i++)
- {
- Console.WriteLine(Thread.CurrentThread.Name + "系統(tǒng)當(dāng)前時(shí)間毫秒值:" + DateTime.Now.Millisecond.ToString());
- Thread.Sleep(parameter.Interval);//讓線程暫停
- }
- }
- }
- }
- }
第二種方法和上面方法有些相似,也是需要引入外部類,并且將Thread實(shí)例放在引入的類中,這種情況適合于在線程中處理的業(yè)務(wù)邏輯比較復(fù)雜的情況。在前不久處理的一個(gè)項(xiàng)目中我用過(guò)這種情況,它是用來(lái)實(shí)現(xiàn)雙向數(shù)據(jù)傳輸?shù)摹?/P>
如果實(shí)現(xiàn)上面的效果,代碼如下:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace StartThread
- {
- class MyThreadParameter
- {
- private int interval;
- private int loopCount;
- private Thread thread;
- ///
- /// 構(gòu)造函數(shù)
- ///
- /// 線程的暫停間隔
- /// 循環(huán)次數(shù)
- public MyThreadParameter(int interval,int loopCount)
- {
- this.interval = interval;
- this.loopCount = loopCount;
- thread = new Thread(new ThreadStart(Run));
- }
- public void Start()
- {
- if (thread != null)
- {
- thread.Start();
- }
- }
- private void Run()
- {
- for (int i = 0; i < loopCount; i++)
- {
- Console.WriteLine("系統(tǒng)當(dāng)前時(shí)間毫秒值:" + DateTime.Now.Millisecond.ToString());
- Thread.Sleep(interval);//讓線程暫停
- }
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- MyThreadParameter parameterThread = new MyThreadParameter(30, 50);
- parameterThread.Start();
- }
- }
- }
上面的代碼的運(yùn)行效果和前面的代碼運(yùn)行效果類似,只不過(guò)是將業(yè)務(wù)處理代碼放在一個(gè)單獨(dú)的類MyThreadParameter中,使得MyThreadParameter看起來(lái)也像一個(gè)Thread,實(shí)際上維護(hù)的還是其內(nèi)部的Thread,在一些大型系統(tǒng)中這樣做的好處是便于維護(hù)。
總結(jié):在本篇主要講述如何啟動(dòng)C#線程的問(wèn)題,在啟動(dòng)時(shí)可能會(huì)遇到無(wú)需參數(shù)、需要多個(gè)參數(shù)的情況,在這里講述了如何解決這些問(wèn)題的思路。在.net類庫(kù)中雖然存在著龐大的類庫(kù),但是并不是總會(huì)有合適的類來(lái)解決我們所遇到的問(wèn)題,但是只要肯動(dòng)腦筋總會(huì)想到合適的辦法。
【編輯推薦】