网摘 |  收藏 | 

三、以ThreadStart方式实现多线程

http://www.cnblogs.com/leslies2/archive/2012/02/07/2310495.html#t3

3.1 使用ThreadStart委托

这里先以一个例子体现一下多线程带来的好处,首先在Message类中建立一个方法ShowMessage(),里面显示了当前运行线程的Id,并使用Thread.Sleep(int ) 方法模拟部分工作。在main()中通过ThreadStart委托绑定Message对象的ShowMessage()方法,然后通过Thread.Start()执行异步方法。

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 < 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.Start();
               Console.WriteLine("Do something ..........!");
               Console.WriteLine("Main thread working is complete!");
               
           }
       }

 

请注意运行结果,在调用Thread.Start()方法后,系统以异步方式运行Message.ShowMessage(),而主线程的操作是继续执行的,在Message.ShowMessage()完成前,主线程已完成所有的操作。

 

3.2 使用ParameterizedThreadStart委托

ParameterizedThreadStart委托与ThreadStart委托非常相似,但ParameterizedThreadStart委托是面向带参数方法的。注意ParameterizedThreadStart 对应方法的参数为object,此参数可以为一个值对象,也可以为一个自定义对象。

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

 

3.3 前台线程与后台线程

注意以上两个例子都没有使用Console.ReadKey(),但系统依然会等待异步线程完成后才会结束。这是因为使用Thread.Start()启动的线程默认为前台线程,而系统必须等待所有前台线程运行结束后,应用程序域才会自动卸载。

在第二节曾经介绍过线程Thread有一个属性IsBackground,通过把此属性设置为true,就可以把线程设置为后台线程!这时应用程序域将在主线程完成时就被卸载,而不会等待异步线程的运行。

 

3.4 挂起线程

为了等待其他后台线程完成后再结束主线程,就可以使用Thread.Sleep()方法。

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(50000);
    }
}

运行结果如下,此时应用程序域将在主线程运行5秒后自动结束

 

但系统无法预知异步线程需要运行的时间,所以用通过Thread.Sleep(int)阻塞主线程并不是一个好的解决方法。有见及此,.NET专门为等待异步线程完成开发了另一个方法thread.Join()。把上面例子中的最后一行Thread.Sleep(5000)修改为 thread.Join() 就能保证主线程在异步线程thread运行结束后才会终止。

 

3.5 Suspend 与 Resume (慎用)

Thread.Suspend()与 Thread.Resume()是在Framework1.0 就已经存在的老方法了,它们分别可以挂起、恢复线程。但在Framework2.0中就已经明确排斥这两个方法。这是因为一旦某个线程占用了已有的资源,再使用Suspend()使线程长期处于挂起状态,当在其他线程调用这些资源的时候就会引起死锁!所以在没有必要的情况下应该避免使用这两个方法。

 

3.6 终止线程

若想终止正在运行的线程,可以使用Abort()方法。在使用Abort()的时候,将引发一个特殊异常 ThreadAbortException 。
若想在线程终止前恢复线程的执行,可以在捕获异常后 ,在catch(ThreadAbortException ex){...} 中调用Thread.ResetAbort()取消终止。
而使用Thread.Join()可以保证应用程序域等待异步线程结束后才终止运行。

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

运行结果如下

posted @ 2012-11-12 17:22  xulonghua219  阅读(174)  评论(0编辑  收藏  举报