ThreadStart 方式實作多線程
先以一個例子展現一下多線程帶來的好處,首先在Message類中建立一個方法ShowMessage(),裡面顯示了目前運作線程的Id,并使用Thread.Sleep(int ) 方法模拟部分工作。在main()中通過ThreadStart委托綁定Message對象的ShowMessage() 方法,然後通過Thread.Start() 執行異步方法
namespace Thread1
{
public class Message
{
public void ShowMessage()
{
string message = string.Format("Async threadId is :{0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
for (int n = 0; n < 100; n++)
{
Thread.Sleep(300);
Console.WriteLine("The number is:" + n.ToString());
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main threadId is:" + Thread.CurrentThread.ManagedThreadId);
Message message = new Message();
Thread thread = new Thread(new ThreadStart(message.ShowMessage));
thread.Start();
Console.WriteLine("Do something ..........!");
Console.WriteLine("Main thread working is complete!");
}
}
}
請注意運作結果,在調用Thread.Start()方法後,系統以異步方式運作Message.ShowMessage(),而主線程的操作是繼續執行的,在Message.ShowMessage()完成前,主線程已完成所有的操作
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cGcq5yM0MDM5UjN3MzY3UDOzAjMzYzX5ETO1UTMzEzLclDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.jpg)
用 ParameterizedThreadStart 委托
ParameterizedThreadStart委托與ThreadStart委托非常相似,但ParameterizedThreadStart委托是面向帶參數方法的。(eg:thread.Start(person)) 注意ParameterizedThreadStart 對應方法的參數為object,此參數可以為一個值對象,也可以為一個自定義對象
namespace Thread2
{
public class Person
{
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
public class Message
{
public void ShowMessage(object person)
{
if (person != null)
{
Person _person = (Person)person;
string message = string.Format("\n{0}'s age is {1}!\nAsync threadId is:{2}",
_person.Name, _person.Age, Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
}
for (int n = 0; n < 10; n++)
{
Thread.Sleep(300);
Console.WriteLine("The number is:" + n.ToString());
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main threadId is:" + Thread.CurrentThread.ManagedThreadId);
Message message = new Message();
//綁定帶參數的異步方法
Thread thread = new Thread(new ParameterizedThreadStart(message.ShowMessage));
Person person = new Person();
person.Name = "Jack";
person.Age = 21;
thread.Start(person); //啟動異步線程
Console.WriteLine("Do something ..........!");
Console.WriteLine("Main thread working is complete!");
}
}
}
前台線程與背景線程
注意以上兩個例子都沒有使用Console.ReadKey(),但系統依然會等待異步線程完成後才會結束。這是因為使用Thread.Start()啟動的線程預設為前台線程,而系統必須等待所有前台線程運作結束後,應用程式域才會自動解除安裝
Thread有一個屬性IsBackground,通過把此屬性設定為true,就可以把線程設定為背景線程!這時應用程式域将在主線程完成時就被解除安裝,而不會等待異步線程的運作
挂起線程
namespace Thread3
{
public class Message
{
public void ShowMessage()
{
string message = string.Format("\nAsync threadId is:{0}",
Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
for (int n = 0; n < 10; n++)
{
Thread.Sleep(300);
Console.WriteLine("The number is:" + n.ToString());
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main threadId is:" + Thread.CurrentThread.ManagedThreadId);
Message message = new Message();
Thread thread = new Thread(new ThreadStart(message.ShowMessage));
thread.IsBackground = true;
thread.Start();
Console.WriteLine("Do something ..........!");
Console.WriteLine("Main thread working is complete!");
Console.WriteLine("Main thread sleep!");
Thread.Sleep(500);
}
}
}
但系統無法預知異步線程需要運作的時間,是以用通過Thread.Sleep(int)阻塞主線程并不是一個好的解決方法。有見及此,.NET專門為等待異步線程完成開發了另一個方法thread.Join()。把上面例子中的最後一行Thread.Sleep(500)修改為 thread.Join() 就能保證主線程在異步線程thread運作結束後才會終止
Suspend 與 Resume (慎用)
Thread.Suspend()與 Thread.Resume()是在Framework1.0 就已經存在的老方法了,它們分别可以挂起、恢複線程。但在Framework2.0中就已經明确排斥這兩個方法。這是因為一旦某個線程占用了已有的資源,再使用Suspend()使線程長期處于挂起狀态,當在其他線程調用這些資源的時候就會引起死鎖!是以在沒有必要的情況下應該避免使用這兩個方法
終止線程
若想終止正在運作的線程,可以使用Abort()方法。在使用Abort()的時候,将引發一個特殊異常 ThreadAbortException
若想線上程終止前恢複線程的執行,可以在捕獲異常後 ,在catch(ThreadAbortException ex){…} 中調用Thread.ResetAbort()取消終止
namespace Thread4
class Program
static void Main(string[] args)
{
Console.WriteLine("Main threadId is:" +
Thread.CurrentThread.ManagedThreadId);
Thread thread = new Thread(new ThreadStart(AsyncThread));
thread.IsBackground = true;
thread.Start();
thread.Join();
}
//以異步方式調用
static void AsyncThread()
{
try
{
string message = string.Format("\nAsync threadId is:{0}",
Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
for (int n = 0; n < 10; n++)
{
//當n等于4時,終止線程
if (n >= 4)
{
Thread.CurrentThread.Abort(n);
}
Thread.Sleep(300);
Console.WriteLine("The number is:" + n.ToString());
}
}
catch (ThreadAbortException ex)
{
//輸出終止線程時n的值
if (ex.ExceptionState != null)
Console.WriteLine(string.Format("Thread abort when the number is: {0}!",
ex.ExceptionState.ToString()));
//取消終止,繼續執行線程
Thread.ResetAbort();
Console.WriteLine("Thread ResetAbort!");
}
//線程結束
Console.WriteLine("Thread Close!");
Thread.Sleep(50000);
}
}
}