class Program { static void Main(string[] args) { Console.WriteLine(); for (int i = 0; i < 10; i++) { Thread newThread = new Thread(Work); // 开启新线程 newThread.Start(); } Console.ReadKey(); } static void Work() { Console.WriteLine(); // 模拟做了一些工作,耗费1s时间 Thread.Sleep(1000); Console.WriteLine(); } }
View Code在主线程中,该代码创建了10个新的线程,这个10个线程的工作互不干扰,宏观上来看它们应该是并行运行的,执行的结果也证实了这一点:
PS:这里再次强调一点,当new了一个Thread类型对象并不意味着生成了一个线程,事实上线程的生成是在调用Thread的Start方法的时候。另外在之前的介绍中,这里的线程并不一定是操作系统层面上产生的一个真正线程!
(2)控制线程的状态
很多时候,我们需要主动关心线程当前所处的状态。在任意时刻,.NET中的线程都会处于如下图所示的几个状态中的某一个状态上,该图也直观地展示了一个线程可能经过的状态转换过程(该图并没有列出所有的状态转换途径/原因):
下面的示例代码则展示了我们如何手动地查看和控制一个线程的状态:
class Program { static void Main(string[] args) { Console.WriteLine(); // 初始化一个线程 thread1 Thread thread1 = new Thread(Work1); // 这时状态:UnStarted PrintState(thread1); // 启动线程 Console.WriteLine(); thread1.Start(); // 这时状态:Running PrintState(thread1); // 让线程飞一会 3s Thread.Sleep(3 * 1000); // 让线程挂起 Console.WriteLine(); thread1.Suspend(); // 给线程足够的时间来挂起,否则状态可能是SuspendRequested Thread.Sleep(1000); // 这时状态:Suspend PrintState(thread1); // 继续线程 Console.WriteLine(); thread1.Resume(); // 这时状态:Running PrintState(thread1); // 停止线程 Console.WriteLine(); thread1.Abort(); // 给线程足够的时间来终止,否则的话可能是AbortRequested Thread.Sleep(1000); // 这时状态:Stopped PrintState(thread1); Console.WriteLine(); Console.WriteLine(); // 初始化一个线程 thread2 Thread thread2 = new Thread(Work2); // 这时状态:UnStarted PrintState(thread2); // 启动线程 thread2.Start(); Thread.Sleep(2 * 1000); // 这时状态:WaitSleepJoin PrintState(thread2); // 给线程足够的时间结束 Thread.Sleep(10 * 1000); // 这时状态:Stopped PrintState(thread2); Console.ReadKey(); } Work1() { Console.WriteLine(); // 模拟线程运行,但不改变线程状态 (true) { } } Work2() { Console.WriteLine(); // 睡眠10s Thread.Sleep(10 * 1000); Console.WriteLine(); } PrintState(Thread thread) { Console.WriteLine(, thread.ThreadState.ToString()); } }
View Code上述代码的执行结果如下图所示:
PS:为了演示方便,上述代码刻意地使线程处于各个状态并打印出来。在.NET Framework 4.0 及之后的版本中,已经不再鼓励使用线程的挂起状态,以及Suspend和Resume方法了。
2.2 如何使用.NET中的线程池?(1).NET中的线程池是神马
我们都知道,线程的创建和销毁需要很大的性能开销,在Windows NT内核的操作系统中,每个进程都会包含一个线程池。而在.NET中呢,也有自己的线程池,它是由CLR负责管理的。