1.线程基础知识

    进程是应用程序运行时的一个实例,它包含:一个内核对象,Windows 操作系统用他来管理进程;一个地址空间,包含所有程序集可执行代码和数据以及对线程堆栈和堆的内存分配。进程拥有自己的属性以及调度优先级,当系统创建一个进程时,会自动创建一个主线程来执行进程地址空间里面的代码,主线程可以创建多个子线程。进程地址空间中的代码没有任何线程执行时,系统就会终止进程和释放地址空间。每个进程至少有一个或多个线程,每个线程都有自己的一个执行上下文环境即一组 CPU 寄存器和堆栈,多个运行线程都在进程的地址空间中同时执行代码,系统会采用轮询的方式为每个线程分配CPU时间片,线程之间就会进行上下文切换。
    线程是应用程序执行的最小单元,线程由一个唯一的线程ID进行标识。每个线程都包含:线程内核对象、线程环境块、用户模式栈、内核模式栈以及DLL 线程连接和线程分离通知等要素,线程都有内存空间和运行时间上的开销。每个线程都会分配0~31的调到优先级,Windows 把线程划分7个相对优先级:Idle、Lowest、BelowNormal、Normal、AboveNormal、Highest和Time-Critical。CLR 保留了Idle和 Time-Critical ,在应用程序中只需要关注其他的5个优先级。CLR 把每个线程看着为前台线程或后台线程,进程中所有的前台线程停止运行时,运行的所有后台线程都会被CLR终止。
     多线程能够提升应用程序的性能,改善用户体验,执行并发任务等,比如:执行复杂业务逻辑或长时间的计算任务、I/O操作、网络请求时,使用后台线程处理这些受限制的任务,就不会阻塞主线。

2.使用 System.Threading.Thread 类创建线程

       在 C# 中可以使用 System.Threading.Thread 类来创建一个线程,该类有4个重要构造函数,每个构造函数都接受一个线程启动时需要执行的函数(委托)以及线程的最大堆栈大小。

public Thread(ParameterizedThreadStart start);
public Thread(ThreadStart start);
public Thread(ParameterizedThreadStart start, int maxStackSize);
public Thread(ThreadStart start, int maxStackSize);

参数委托定义:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

ParameterizedThreadStart 委托允许线程启动时为执行方法传递一个需要使用的数据对象。
使用 Thread 类创建一个线程并执行任务,创建一个线程可以为线程制定线程的名称、优先级、是否为后台线程以及设置线程的区域性等属性。
   1:   private static void CreateThread()
   2:          {
   3:              //创建一个线程,可以构造 System.Threading.ParameterizedThreadStart 委托或 System.Threading.ThreadStart 委托实例
   4:              Thread thread = new Thread(state =>
   5:              {
   6:                  //线程启动时需要执行的任务
   7:                  int sum = 0;
   8:                  //将当前线程挂起指定的时间,这儿是2000毫秒
   9:                  Thread.Sleep(2000);
  10:                  for (int i = 0; i < 1000; i++)
  11:                  {
  12:                      sum++;
  13:                  }
  14:                  Console.WriteLine("计数值:{0}", sum.ToString());
  15:              });
  16:              thread.Name = "执行长时间的计算处理";//设置线程的名称
  17:              thread.Priority = ThreadPriority.AboveNormal;//设置线程优先级
  18:              thread.CurrentCulture = new System.Globalization.CultureInfo("EN");//设置线程区域性
  19:              Thread thread2 = new Thread(() => {
  20:                  Thread.Sleep(2000);
  21:                  Console.WriteLine("执行复杂任务");
  22:              });
  23:              //启动线程,可以传递一个线程执行方法所使用的数据对象
  24:              thread.Start(null);
  25:              thread2.Start();
  26:          }

  3.Thread 类的一些重要的方法和属性

     Thread.Sleep 静态方法将当前线程挂起指定的时间,可以接受一个Int类型的表示挂起线程的毫秒数或TimeSpan类型的时间值。

   1:   static void Main(string[] args)
   2:          {
   3:              Thread t = new Thread(new ThreadStart(() => {
   4:                  Console.WriteLine("当前线程将会被阻塞1秒钟。");
   5:                  Thread.Sleep(1000);
   6:                  Console.WriteLine("当前线程被阻塞1秒以后继续执行。");
   7:              }));
   8:              t.Start();
   9:              Console.WriteLine("主线程执行任务。");
  10:          }

子线程会被阻塞1秒钟。

执行结果:image

    Join 方法会阻塞调用线程,直到某个线程终止或经过了指定时间为止。

   1:   static void Main(string[] args)
   2:          {
   3:              Console.WriteLine("主线程开始执行任务。");
   4:              Thread t = new Thread(new ThreadStart(() => {
   5:                  Console.WriteLine("子线程执行任务,并阻塞调用线程。");
   6:                
   7:              }));
   8:              t.Start();
   9:              //调用线程被阻塞2000毫秒
  10:              t.Join(2000);
  11:              Console.WriteLine("主线程被阻塞后继续执行任务。");
  12:          }
  程序执行结果:image

    Interrupt  方法中断处于 WaitSleepJoin 线程状态的线程,可以通过线程的 ThreadState 属性获得当前线程的状态,每个线程都具有如下的状态:

   1:  public enum ThreadState
   2:      {
   3:          Running = 0,
   4:          StopRequested = 1, 
   5:          SuspendRequested = 2,
   6:          Background = 4,
   7:          Unstarted = 8,
   8:          Stopped = 16,
   9:          WaitSleepJoin = 32,
  10:          Suspended = 64,
  11:          AbortRequested = 128,
  12:          Aborted = 256,
  13:      }

程序示例:

1: static void Main(string[] args)

   2:          {
   3:              Console.WriteLine("主线程开始执行任务。");
   4:              Thread t = null;
   5:                t=  new Thread(new ThreadStart(() => {
   6:                  Thread.Sleep(2000);
   7:                  Console.WriteLine("子线程执行任务。");
   8:              }));
   9:              Console.WriteLine("调用Start方法前子线程的状态:{0}",t.ThreadState.ToString());
  10:              t.Start();
  11:              Console.WriteLine("调用Start方法后子线程当前状态:{0}", t.ThreadState.ToString());
  12:              //调用线程被阻塞2000毫秒
  13:              t.Join(2000);
  14:              Console.WriteLine("调用Join方法后子线程的状态:{0}", t.ThreadState.ToString());
  15:              Thread.Sleep(1000);
  16:              //终止处于 WaitSleepJoin 状态的的线程。
  17:              t.Interrupt();
  18:              Console.WriteLine("调用Interrupt方法后子线程的状态:{0}", t.ThreadState.ToString());
  19:              Console.WriteLine("主线程被阻塞后继续执行任务。");
  20:          }

执行结果image

      Abort 方法在调用此方法的线程上引发 System.Threading.ThreadAbortException 异常,以开始终止此线程的过程。

   1:   static void Main(string[] args)
   2:          {
   3:              Thread t = null;
   4:              t = new Thread(() =>
   5:                  {
   6:                      try
   7:                      {
   8:                          Thread.Sleep(1000);
   9:                          Console.WriteLine("子线程执行任务。");
  10:                      }
  11:                      catch
  12:                      {
  13:                          Console.WriteLine("子线程引发终止异常,线程状态:{0}。", Thread.CurrentThread.ThreadState.ToString());
  14:                      }
  15:                      finally
  16:                      {
  17:                          Console.WriteLine("进入finally块语句子线程状态:{0}。", Thread.CurrentThread.ThreadState.ToString());
  18:                      }
  19:                  });
  20:              t.Start();
  21:              Thread.Sleep(1000);
  22:              //终止子线程
  23:              t.Abort();
  24:              t.Join();
  25:              Console.WriteLine("子线程线程状态:{0}。", t.ThreadState.ToString());
  26:          }

执行结果:image

     Suspend 方法挂起线程和Resume 继续已挂起的线程,这两个方法已经过时。

    线程的重要属性:

     Thread.CurrentContext 静态属性获取线程正在其中执行的当前上下文。

     Thread.CurrentThread 静态属性获取当前正在运行的线程。

     Name 获取或设置线程的名称。

     IsAlive 获取当期线程的执行状态。

     IsBackground 获取或设置线程是否为后台线程。

     IsThreadPoolThread 指示一个线程是否属于托管线程池线程。

     ManagedThreadId 获取当前线程的唯一标识符。

     Priority 获取或设置线程的调度优先级。

     ThreadState 获取当前线程的状态。

关于线程的具体详情参见MSDN对 System.Threading.Thread 类的描述。

本文只是简单的介绍了线程的基础知识以及使用和一些方法属性,需要在具体业务中实践,合理使用线程这种宝贵的资源以提升应用程序性能。

posted on 2012-12-13 22:56  pengstone  阅读(3907)  评论(0编辑  收藏  举报