天天看點

C#多線程(二) -- ThreadStart

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()完成前,主線程已完成所有的操作

C#多線程(二) -- ThreadStart

用 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!");

        }
    }
}      
C#多線程(二) -- ThreadStart

前台線程與背景線程

注意以上兩個例子都沒有使用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);
        }
    }
}      
C#多線程(二) -- ThreadStart

但系統無法預知異步線程需要運作的時間,是以用通過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);
        }
    }
}