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操作、网络请求时,使用后台线程处理这些受限制的任务,就不会阻塞主线。
在 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秒钟。
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: }
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: }
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: }
Suspend 方法挂起线程和Resume 继续已挂起的线程,这两个方法已经过时。
线程的重要属性:
Thread.CurrentContext 静态属性获取线程正在其中执行的当前上下文。
Thread.CurrentThread 静态属性获取当前正在运行的线程。
Name 获取或设置线程的名称。
IsAlive 获取当期线程的执行状态。
IsBackground 获取或设置线程是否为后台线程。
IsThreadPoolThread 指示一个线程是否属于托管线程池线程。
ManagedThreadId 获取当前线程的唯一标识符。
Priority 获取或设置线程的调度优先级。
ThreadState 获取当前线程的状态。
关于线程的具体详情参见MSDN对 System.Threading.Thread 类的描述。
本文只是简单的介绍了线程的基础知识以及使用和一些方法属性,需要在具体业务中实践,合理使用线程这种宝贵的资源以提升应用程序性能。