多线程概述
什么是进程?
当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。
什么是线程?
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。
什么是多线程?
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
多线程的好处
可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。
多线程的不利方面
线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 多线程需要协调和管理,所以需要CPU时间跟踪线程; 线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;线程太多会导致控制太复杂,最终可能造成很多Bug;
.NET中的多线程
一、创建线程
我们可以使用Thread类的构造函数创建线程,用无参数的TheadStart委托或者带有一个参数的ParameterizedTheadStart委托作为构造函数的参数即可。线程执行其实就是执行里边的线程函数——即里边的委托函数!
public delegate void ThreadStart(); public delegate void ParameterizedThreadStart(object obj);
举个栗子:
static void Main() { Thread t = new Thread(new TheadStart(Go)); //Thread t = new Thead(Go); t.Start(); } static void Go() { Console.Write("hello!"); } static void Main() { Thread t = new Thread(Go); t.Start("hello"); Go(); } static void Go(object msg) { string message = (string)msg; Console.Write(message); }
二、启动线程
start():将当前线程的状态更改为 ThreadState.Running。
一旦线程处于 ThreadState.Running 状态,操作系统就可以安排其执行。 线程从方法的第一行(由提供给线程构造函数的 ThreadStart 或 ParameterizedThreadStart 委托表示)开始执行。线程一旦终止,它就无法通过再次调用 Start 来重新启动。
三、线程睡眠
Thread.Sleep(int ms); Thread.Sleep(TimeSpan timeout);
上述方法为Thread类的两个静态方法,用来阻止当前线程指定的时间。
四、终止线程
使用Abort方法实现,用于永久地停止托管线程。一旦线程被中止,它将无法重新启动。Abort会引发ThreadAbortException异常,同时可以传递一个终止的参数信息。
Thread.Abort();
Thread.Abort(Object stateInfo);
注意:Suspend和Resume为废弃方法,不要使用!
五、线程属性
5.1、线程名字
每个线程都有一个Name属性,可以设置和修改,但是只能设置一次。
5.2、后台线程
在.net中线程分为前台线程和后台线程,在一个进程中,当所有前台线程停止运行时,CLR会强制结束仍在运行的任何后台线程,这些后台线程直接被终止,不会抛出异常。所以我们应该在前台线程中执行我们确实要完成的事情!
static void Main(string[] args) { Thread t = new Thread(Test); t.IsBackground = true; //这里线程是后台线程,应用程序马上结束 //假如是前台线程,大约5秒以后结束 t.Start(); Console.WriteLine("A"); } static void Test() { Thread.Sleep(5 * 1000); Console.WriteLine("B"); }
5.3、线程优先级
线程的优先级使用Priority设置或获取,只有在运行时才有作用,分为5个级别:
enum ThreadPriority{Lowest, BelowNormal , Normal, AboveNormal, Highest}
举个栗子:
myThread.Priority=ThreadPriority.Lowest;
注意:优先等级高的线程占用更多的CUP时间。 但是当优先等级高的线程正在等待一些资源的时候,优先等级低的线程可以运行。
六、阻塞线程
阻塞某个线程用的方法是join()。这个方法可以让并发处理变得串行化,让主线程去等待某个线程执行完毕才继续往下执行!
class Test { static void Main() { Thread t = new Thread(Run); t.Start(); //Join相当于把Run方法内嵌如此 t.Join(); //该死的t.Join(),害的我主线程必须在你执行完后才能执行。 Console.WriteLine("我是主线程:" + Thread.CurrentThread.GetHashCode()); } static void Run() { //等待5s Thread.Sleep(5000); Console.WriteLine("我是线程:" + Thread.CurrentThread.GetHashCode()); } }
七、线程的异常处理
线程的异常都是在线程函数里边解决的,因此应该把try catch放在线程的委托函数里边~
static void Main(string[] args) { try { new Thread(Go).Start(); } catch (Exception ex) { Console.Write(ex.Message); } Console.ReadKey(); } static void Go() { try { ///处理逻辑 } catch(Exception e) { Console.Write(e.Message); } }
注意:在调用Abort方法终止一个线程时,在异常处理的时候为了防止程序再次抛出异常,在catch里边处理完异常之后最好加上Thread.ResetAbort();这条语句!