C# 创建线程的多种方式之Thread类

1、Thread类创建线程

该类的构造函数可以接受ThreadStart委托参数(定义了无参,返回void的函数),以及ParameterizedThreadStart委托参数(定义了Object参数,返回void的函数)。.

       static void Main(string[] args)
        {
            
            Console.WriteLine("Main Start....");
            Thread t1 = new Thread(Calculate);
            t1.Start(10);
            Console.WriteLine("Main is over");
            Console.ReadLine();
        }

        private static void Calculate(object obj)
        {
            int sum = 0;
            int total = (int)obj;
            for (int i = 0; i < total;i++ )
            {
                sum += i;
                Thread.Sleep(100);
            }
             Console.WriteLine("Sum is "+sum);
        }

当然Thread类也可以和Lamda表达式一起使用,实现与上面同样的功能:

      static void Main(string[] args)
        {
            
            Console.WriteLine("Main Start....");
            Thread t1 = new Thread((obj) =>
            {
                int sum = 0;
                int total = (int)obj;
                for (int i = 0; i < total; i++)
                {
                    sum += i;
                    Thread.Sleep(100);
                }
                Console.WriteLine("Sum is " + sum);
            });
            t1.Start(10);
            Console.WriteLine("Main is over");
            Console.ReadLine();
        }

2、后台线程

只要有一个前台在运行,应用进程就不会停止运行,而后台线程的运行则不会影响应用进程的结束,前,后台线程在线程优先级及其他方面并无差异。在默认情况下,Thread类创建的线程都是前台线程,也可以通过设置IsBackground属性改变为后台线程,而线程池创建的均为后台线程。如下,将Console.ReadLine();指令禁用,运行发现控制台窗体不会马上消失,而是会等待t1线程运行结束。

       static void Main(string[] args)
        {
            
            Console.WriteLine("Main Start....");
            Thread t1 = new Thread((obj) =>
            {
                int sum = 0;
                int total = (int)obj;
                for (int i = 0; i < total; i++)
                {
                    sum += i;
                    Thread.Sleep(100);
                }
                Console.WriteLine("Sum is " + sum);
            });
            t1.Start(10);
            Console.WriteLine("Main is over");
            //Console.ReadLine();
        }

3、线程优先级

线程优先级用Priority属性表示,定义的级别有Highest, AboveNormal, BelowNormal, Lowest, 操作系统会根据优先级去调度线程。如果有优先级相同的几个线程在运行,就用得上时间量和循环的规则。如果线程是CPU密集型的(一直需要CPU不等待的),其优先级就低于定义的基本优先级。

4、线程的控制及状态

ThreadState 为线程定义了一组所有可能的执行状态。一旦线程被创建,它就至少处于其中一个状态中,直到终止。因为是各种状态的组合,所以在判断当前线程状态的时候就需要用位运算,而不能简单的使用等号(有个例外,Runing状态值为0,所以用与运算不行)。

  • Unstarted : 创建线程,但为调用Run();

  • Runing: 调用Run()后,当线程正在被CPU调用;

  • WaitSleepJoin:线程等待,调用Sleep(), Join()会进入该状态,其中Join()会阻塞当前线程,直到被调用线程运行结束或中止;

  • Stopped:线程运行结束后,进入该状态,该状态下无法通过Start(),重新启动线程,必须重新创建线程;

  • Background:当线程的IsBackground属性设置为true后,创建线程后调用线程前,状态为Unstarted+Background,而调用线程后状态为Runing+Background,sleep()后状态为WaitSleepJoin+Background,线程结束后状态为Stopped;

  • AbortRequested:当线程调用Abort(),处理完ThreadAbortException前,此时可以调用ResetAbort(),取消中止操作;

  • Aborted:当线程调用Abort(),处理完ThreadAbortException后;

  • SuspendRequested:当线程调用Suspend()后,线程被挂起前;

  • Suspended:线程已经被挂起,此时可用Resume(),继续运行;

控制线程的常用函数在上面基本上已经提到,其中Suspend(), Resume()已经不推荐使用,因为线程挂起可能会造成一些不可预知的问题,例如线程死锁,可以使用线程同步的一些类来代替使用。另外,Abort()也是不推荐使用的,可以定义布尔状态量来代替使用。Interrupt()上面未提到,调用这个函数后,会出现InterruptException,接着唤醒处于WaitSleepJoin状态的线程。