一:線程
在.net中提供了兩種啟動線程的方式,一種是不帶參數的啟動方式,另一種是帶參數的啟動的方式。
不帶參數的啟動方式
如果啟動參數時無需其它額外的信息,可以使用ThreadStart來實例化Thread:
帶參數的啟動方法
帶參數,就不能用ThreadStart委托作為構造函數的參數來實例化Thread了,而要 ParameterizedThreadStart委托,和ThreadStart一樣的是它也是線程啟動時要執行的方法,和ThreadStart不同 的是,它在實例化時可以用一個帶有一個Object參數的方法作為構造函數的參數,而實例化ThreadStart時所用到的方法是沒有參數的。 為 什么是Object這樣的參數呢?很簡單,因為在.net中Object是所有類型的基類,用它可以表示Array(數組)、Interface(接 口)、ValueType(值類型,如bool,byte,char,short,int,float,long,double等)、class(類) 等.net中的類型。當然,這也意味着如果你要啟動一個線程,給它傳遞一個int類型參數時,必須在啟動方法中進行相應的類型轉換。
這種object類型的參數可以定義一個有多個屬性的類來進行,或者用$隔開的字符串,使用的時候分解為數組來用
簡單實例代碼:
//不帶參數 ThreadStart ts = new ThreadStart(ThreadFunc); Thread t = new Thread(ts); t.Start(); //帶參數 ParameterizedThreadStart ParStart = new ParameterizedThreadStart(GoTo); Thread myThread = new Thread(ParStart); object o = (object)txt_url.Text; myThread.Start(o);
詳細實例代碼:
Program p = new Program(); Thread nonParameterThread = new Thread(new ThreadStart(p.NonParameterRun)); nonParameterThread.Start(); Thread parameterThread = new Thread(new ParameterizedThreadStart(p.ParameterRun)); parameterThread.Name = "Thread A:"; parameterThread.Start(30); /// <summary> /// 不帶參數的啟動方法 /// </summary> public void NonParameterRun() { for (int i = 0; i < 10; i++) { Console.WriteLine("系統當前時間毫秒值:"+DateTime.Now.Millisecond.ToString()); Thread.Sleep(200);//讓線程暫停 } } /// <summary> /// 帶參數的啟動方法 /// </summary> /// <param name="ms">讓線程在運行過程中的休眠間隔</param> public void ParameterRun(object ms) { int j = 10; int.TryParse(ms.ToString(), out j);//這里采用了TryParse方法,避免不能轉換時出現異常 for (int i = 0; i < 10; i++) { Console.WriteLine(Thread.CurrentThread.Name+"系統當前時間毫秒值:" + DateTime.Now.Millisecond.ToString()); Thread.Sleep(j);//讓線程暫停 } }
二:委托
委托就是講方法以參數的形式進行傳遞
private static void WriteStrToFile(string txt) { write(txt); } private delegate void WriteStrToFileDelegate(string txt);//定義委托 new WriteStrToFileDelegate(WriteStrToFile).BeginInvoke(txt, null, null);//異步使用委托
再舉一例:
public delegate void GreetingDelegate(string name);//定義委托 //定義兩方法 private static void EnglishGreeting(string name) { Console.WriteLine("Morning, " + name); } private static void ChineseGreeting(string name) { Console.WriteLine("早上好, " + name); }
使用:
private static void GreetPeople(string name, GreetingDelegate MakeGreeting) { MakeGreeting(name);//這里默認同步方式,與MakeGreeting.Invoke(name)效果一樣 } //使用 GreetPeople("Jimmy Zhang", EnglishGreeting); GreetPeople("張子陽", ChineseGreeting);
實際上,我們可以也可以繞過GreetPeople方法,通過委托來直接調用EnglishGreeting和ChineseGreeting:
GreetingDelegate delegate1; delegate1 = EnglishGreeting; // 先給委托類型的變量賦值 delegate1 += ChineseGreeting; // 給此委托變量再綁定一個方法 // 將先后調用 EnglishGreeting 與 ChineseGreeting 方法 delegate1 ("Jimmy Zhang"); Console.ReadKey();
委托的Invoke方法用來進行同步調用。同步調用也可以叫阻塞調用,它將阻塞當前線程,然后執行調用,調用完畢后再繼續向下進行。同步調用會阻塞線程,如果是要調用一項繁重的工作(如大量IO操作),可能會讓程序停頓很長時間,造成糟糕的用戶體驗,這時候異步調用就很有必要了。
異步調用不阻塞線程,而是把調用塞到線程池中,程序主線程或UI線程可以繼續執行。
委托的異步調用通過BeginInvoke和EndInvoke來實現。
比較:
在實例化Thread的實例,需要提供一個委托,在實例化這個委托時所用到的參數是線程將來啟動時要運行的方法。
委托其實也是一個線程
MethodInvoker mi = new MethodInvoker(DoPay);//定義委托 this.BeginInvoke(mi);
這里MethodInvoker
只是一個委托, 我們可以認為所有沒有參數的返回值為void的委托和 MethodInvoker 是一樣的, 他們都可以委托到沒有參數的返回值為void的方法。
你自己寫一個 Public Delegate Sub ABC, 這個時候ABC和MethodInvoker是完全一樣的。所以.Net 提供這個只是為了方便你編寫,省得你自己再寫一堆一樣的委托了。