多线程
- 线程 被定义为程序的执行流。每个线程都定义了一个单独的控制流。如果应用程序涉及到复杂的和耗时的操作,那么将程序分成多个线程执行流往往是有益的,每个线程执行特定的工作。
- 线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。
- 为了同时执行多个任务,一个程序可以被划分为更小的线程。
线程生命周期
线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。
- 未启动状态:当线程实例被创建但Start方法未被调用时的状况。
- 就绪状态:当调用了Start,线程准备好运行并等待 CPU 周期时的状况。
- 不可运行状态:下面的几种情况下线程是不可运行的:
- 已经调用 Sleep 方法
- 已经调用 Wait 方法
- 通过 I/O 操作阻塞
- 死亡状态:当线程已完成执行或已中止时的状况。
主线程
- 在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。
- 当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread 属性访问线程。
创建线程
构造函数
#ThreadStart:#public delegate void ThreadStart();//一个无参数,无返回值的委托#ParameterizedThreadStart:#public delegate void ParameterizedThreadStart(object obj);//一个有一个参数、但无返回值的委托#maxStackSize:线程要使用的最大堆栈大小(以字节为单位);如果为 0 则使用可执行文件的文件头中指定的默认最大堆栈大小。 重要地,对于部分受信任的代码,如果 maxStackSize 大于默认堆栈大小,则将其忽略。 不引发异常。public Thread(ThreadStart start);public Thread(ParameterizedThreadStart start);public Thread(ThreadStart start, int maxStackSize);public Thread(ParameterizedThreadStart start, int maxStackSize);
新建线程
public static void CallToChildThread(){ Console.WriteLine("Child thread starts");}ThreadStart childref = new ThreadStart(CallToChildThread);Thread childThread = new Thread(childref);childThread.Start();
调用Start之后,一个线程就进入了就绪状态了,等着CPU分配时间片即可。
以上,就是C#的多线程基本知识,如果你只是需要偶尔在程序中使用以下多线程,那么上面的知识就够你启动一个子线程,并将想要执行的任务放到子线程中执行了。
但如果你在线程中大量使用多线程,那么就可能遇到诸如:线程同步、死锁、控制线程状态等需求。
前后线程&后台线程
#获取或设置一个值,该值指示某个线程是否为后台线程。public bool IsBackground { get; set; }
.Net的公用语言运行时(Common Language Runtime,CLR)能区分两种不同类型的线程:前台线程和后台线程。
这两者的区别就是:
- 应用程序必须运行完所有的前台线程才可以退出;
- 对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
.NET环境使用Thread建立的线程默认情况下是前台线程,即线程属性IsBackground=false,在进程中,只要有一个前台线程未退出,进程就不会终止。主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止。
一般后台线程用于处理时间较短的任务,如在一个Web服务器中可以利用后台线程来处理客户端发过来的请求信息。而前台线程一般用于处理需要长时间等待的任务,如在Web服务器中的监听客户端请求的程序,或是定时对某些系统资源进行扫描的程序。
- 应用程序的主线程以及使用Thread构造的线程都默认为前台线程
- 线程池线程也就是使用 ThreadPool.QueueUserWorkItem()和Task工厂创建的线程都默认为后台线程
线程执行状态(IsAlive)
#获取一个值,该值指示当前线程的执行状态。#如果此线程已启动并且尚未正常终止或中止,则为 true;否则为 false。public bool IsAlive { get; }
线程状态(ThreadState)
#获取一个值,该值包含当前线程的状态#System.Threading.ThreadState 值之一(Running、StopRequested、SuspendRequested、Background、Unstarted、Stopped、WaitSleepJoin、Suspended、AbortRequested、Aborted),它指示当前线程的状态。 初始值为 Unstarted。public ThreadState ThreadState { get; }
线程归属(IsThreadPoolThread)
#获取一个值,该值指示线程是否属于托管线程池。#如果此线程属于托管线程池,则为 true;否则为 false。public bool IsThreadPoolThread { get; }
线程标识符(ManagedThreadId)
#获取当前托管线程的唯一标识符。#一个整数,表示此托管线程的唯一标识符。public int ManagedThreadId { get; }
线程名字(Name)
#获取或设置线程的名称。#包含线程名称的字符串,或者如果未设置名称,则为 null。public string Name { get; set; }
线程优先级(Priority)
#获取或设置一个值,该值指示线程的调度优先级。#System.Threading.ThreadPriority(Lowest、BelowNormal、Normal、AboveNormal、Highest) 值之一。 默认值为 Normal。public ThreadPriority Priority { get; set; }
立即执行当前线程,同时阻塞其余线程
#在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止或经过了指定时间为止。#如果线程已终止,则为 true;如果线程在经过了 millisecondsTimeout 参数指定的时间量后未终止,则为 false。public void Join();public bool Join(int millisecondsTimeout);public bool Join(TimeSpan timeout);
这个方法可以使当前线程立即执行,如果没有参数,则会一直等到当前线程执行结束,如果有参数,则当过时间之后,就会取消这种超级优先级状态。
挂起线程与继续挂起线程
#挂起线程,或者如果线程已挂起,则不起作用。public void Suspend();#继续已挂起的线程。public void Resume();
线程休眠(sleep)
#timeout:设置为线程被阻塞的时间量的 System.TimeSpan。 指定零以指示应挂起此线程以使其他等待线程能够执行。 指定 System.Threading.Timeout.Infinite以无限期阻止线程。public static void Sleep(TimeSpan timeout);#线程被阻塞的毫秒数。 指定零 (0) 以指示应挂起此线程以使其他等待线程能够执行。 指定 System.Threading.Timeout.Infinite以无限期阻止线程。public static void Sleep(int millisecondsTimeout);#当前线程暂停 5000 毫秒int sleepfor = 5000;Thread.Sleep(sleepfor);
销毁线程(Abort)
- Abort() 方法用于销毁线程。
- 通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。
#在调用此方法的线程上引发 System.Threading.ThreadAbortException&#xff0c;以开始终止此线程的过程。 调用此方法通常会终止线程。public void Abort(object stateInfo);public void Abort();public static void CallToChildThread(){ try{ Console.WriteLine("Child thread starts"); // 计数到 10 for (int counter &#61; 0; counter <&#61; 10; counter&#43;&#43;) { Thread.Sleep(500); Console.WriteLine(counter); } Console.WriteLine("Child Thread Completed"); } catch (ThreadAbortException e) { Console.WriteLine("Thread Abort Exception"); } finally { Console.WriteLine("Couldn&#39;t catch the Thread Exception"); }}static void Main(string[] args){ ThreadStart childref &#61; new ThreadStart(CallToChildThread); Console.WriteLine("In Main: Creating the Child thread"); Thread childThread &#61; new Thread(childref); childThread.Start(); // 停止主线程一段时间 Thread.Sleep(2000); // 现在中止子线程 Console.WriteLine("In Main: Aborting the Child thread"); childThread.Abort(); Console.ReadKey(); }
当上面的代码被编译和执行时&#xff0c;它会产生下列结果&#xff1a;
In Main: Creating the Child threadChild thread starts012In Main: Aborting the Child threadThread Abort ExceptionCouldn&#39;t catch the Thread Exceptio
一个每日更新的干货公众号