[.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 利用多线程提升程序性能(上)html
本节导读:编程
随着硬件和网络的高速发展,为多线程(Multithreading)处理并行任务,提供了有利条件。服务器
其实咱们每时每刻都在享受多线程带来的便利,多核处理器多线程工做、Windows操做系统、Web服务器都在使用多线程工做。网络
使用多线程直接提升了程序的执行效率,所以学习多线程对提升程序运行能力很是必要,本节主要介绍多线程原理及.NET中多线程在.NET面向对象程序设计中的应用。 多线程
读前必备: 并发
本节须要了解Lambda表达式基础及匿名方法和匿名委托相关知识; 性能
A. 委托 [.net 面向对象编程基础] (20) 委托 学习
B. Lamda表达式 [.net 面向对象程序设计进阶] (5) Lamda表达式(一) 建立委托 测试
1. 关于多线程spa
在介绍多线程以前,先了解一下进程。
进程:独立运行的程序称为进程。(好比Windows系统后台程序,也能够称为后台进程)
线程:对于同一个程序分为多个执行流,称为线程。
多线程:使用多个线程进行多任务处理,称为多线程。
2. 如何合理使用多线程?
A.对于用户等待程序处理时,可使用多线程处理耗时任务;
B.对于一些不须要即时完成的任务,可使用后台任务线程处理;
C.对于多并发任务,可使用多线程同时处理;
D.对于通信类,好比对线程阻塞,可使用多线程。
除过上面的几个经常使用的状况,还有不少状况下可使用多线程。
3. 多线程的缺点
线程天然也有缺点,如下列出了一些:
A.若是有大量的线程,会影响性能,由于操做系统须要在他们之间切换;
B.更多的线程须要更多的内存空间;
C.线程会给程序带来更多的bug,所以要当心使用,好比:线程任务在执行完成后,要及时释放内存;
D.线程的停止须要考虑其对程序运行的影响。
4. .NET中的两种多线程
.NET自己就是一个多线程的的环境。
在.NET中有两种多线程的:
一种是使用Thread类进行线程的建立、启动,终止等操做。
一种是使用ThreadPool类用于管理线程池.
5 .NET中使用Thread进行多线程处理
5.1 Thread类经常使用方法
.NET基础类库的System.Threading命名空间提供了大量的类和接口支持多线程。System.Threading.Thread类是建立并控制线程,设置其优先级并获取其状态最为经常使用的类。
下面是该类几个相当重要的方法:
Thread.Start():启动线程的执行;
Thread.Suspend():挂起线程,或者若是线程已挂起,则不起做用;
Thread.Resume():继续已挂起的线程;
Thread.Interrupt():停止处于Wait或者Sleep或者Join线程状态的线程;
Thread.Join():阻塞调用线程,直到某个线程终止时为止
Thread.Sleep():将当前线程阻塞指定的毫秒数;
Thread.Abort():以开始终止此线程的过程。若是线程已经在终止,则不能经过Thread.Start()来启动线程。
下面是一个简单的线程示例:
先建立一个方法:
//简单线程方法 static void MyThreadStart() { Console.WriteLine("我是一个简单线程"); }
建立线程调用方法:
//简单的线程 Thread myThread = new Thread(MyThreadStart); myThread.Start();
运行结果以下:
5.2 Thread类经常使用属性
Thread的属性有不少,咱们先看最经常使用的几个:
CurrentThread :用于获取当前线程;
ThreadState 当前线程的状态(5.4介绍);
Name:获取或设置线程名称;
Priority:获取或设置线程的优先级(5.5介绍)
ManagedThreadId:获取当前线程的惟一标识
IsBackground:获取或设置线程是前台线程仍是后台线程(5.6介绍)
IsThreadPoolThread:获取当前线程是不是托管线程池(后面章节会介绍)
下面建立一个线程示例,来讲明这几个属性:
Thread myThreadTest = new Thread(() => { Thread.Sleep(1000); Thread t = Thread.CurrentThread; Console.WriteLine("Name: " + t.Name); Console.WriteLine("ManagedThreadId: " + t.ManagedThreadId); Console.WriteLine("State: " + t.ThreadState); Console.WriteLine("Priority: " + t.Priority); Console.WriteLine("IsBackground: " + t.IsBackground); Console.WriteLine("IsThreadPoolThread: " + t.IsThreadPoolThread); }) { Name = "线程测试", Priority = ThreadPriority.Highest }; myThreadTest.Start(); Console.WriteLine("关联进程的运行的线程数量:"+System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
运行结果以下:
5.3 带参数的线程方法
首先咱们使用Lambda表达式来改写前面“简单线程”中无参数的方法,以下:
//线程一 new Thread(()=>{ for (int i = 0; i < 5; i++) Console.WriteLine("个人线程一-[{0}]", i); }).Start();
运行结果以下:
上面示例建立的线程并无带参数,若是是一个有参数的方法,线程该如何建立?
别担忧,.NET为咱们提供了一个ParameterizedThreadStart委托来解决带一个参数的问题,以下:
//线程二 new Thread((num) =>{ for (int i = 0; i < (int)num; i++) Console.WriteLine("个人线程二--[{0}]", i); }).Start(5);
运行结果以下:
那么问题来了,ParameterizedThreadStart委托只有一个包含数据的参数,对于多个参数呢?咱们可使用一个无参数的方法来包装它,以下:
先建立一个带参数的方法:
static void myThreadStart(int numA, int numB) { for (int i = (int)numA; i < (int)numB; i++) Console.WriteLine("个人线程三---[{0}]", i); }
而后经过无参数的委托来包装它,以下:
//线程三 new Thread(() =>myThreadStart(0,5)).Start();
运行结果以下:
5.4 Thread状态
咱们对于线程启动之后,如何进行挂起和终止、从新启用,首先线程在运行后有一个状态。
System.Threading.Thread.ThreadState属性定义了执行时线程的状态。线程从建立到线程终止,它必定处于其中某一个状态。
A.Unstarted:当线程被建立时,它处在Unstarted状态。
B.Running:Thread类的Start() 方法将使线程状态变为Running状态,线程将一直处于这样的状态,除非咱们调用了相应的方法使其挂起、阻塞、销毁或者天然终止。
C.Suspended:若是线程被挂起,它将处于Suspended状态。
D.Running:咱们调用resume()方法使其从新执行,这时候线程将从新变为Running状态。一
E.Stopped:旦线程被销毁或者终止,线程处于Stopped状态。处于这个状态的线程将不复存在,正如线程开始启动,线程将不可能回到Unstarted状态。
F.Background:线程还有一个Background状态,它代表线程运行在前台仍是后台。在一个肯定的时间,线程可能处于多个状态。
G.WaitSleepJoin、AbortRequested:举例子来讲,一个线程被调用了Sleep而处于阻塞,而接着另一个线程调用Abort方法于这个阻塞的线程,这时候线程将同时处于WaitSleepJoin和AbortRequested状态。
H.一旦线程响应转为Sle阻塞或者停止,当销毁时会抛出ThreadAbortException异常。
ThreadState枚举的10种执行状态以下:
对于线程阻塞和同步问题,将在下一节继续介绍。
5.5. 线程优先级
对于多线程任务,咱们能够根据其重要性和运行所须要的资源状况,设置他的优先级
System.Threading.ThreadPriority枚举了线程的优先级别,从而决定了线程可以获得多少CPU时间。
高优先级的线程一般会比通常优先级的线程获得更多的CPU时间,若是不止一个高优先级的线程,操做系统将在这些线程之间循环分配CPU时间。
低优先级的线程获得的CPU时间相对较少,当这里没有高优先级的线程,操做系统将挑选下一个低优先级的线程执行。
一旦低优先级的线程在执行时遇到了高优先级的线程,它将让出CPU给高优先级的线程。
新建立的线程优先级为通常优先级,咱们能够设置线程的优先级别的值,以下面所示:
对于线程的优先级咱们下面作一个实验,开启两个线程(一个设置高优先级,另外一个设置低优先级)。
分别委托两个方法进行累加,看一下最终结果,代码以下:
int numberA = 0, numberB = 0; bool state = true; new Thread(() => { while (state)numberA++; }) { Priority = ThreadPriority.Highest, Name="线程A" }.Start(); new Thread(() => { while (state)numberB++; }) { Priority = ThreadPriority.Lowest , Name="线程B" }.Start(); //让主线程挂件1秒 Thread.Sleep(1000); state = false; Console.WriteLine("线程A: {0}, 线程B: {1}", numberA, numberB);
运行结果以下:
.NET根据优先级分配了资源,能够看到优先级较高的线程执行的机会较大,但优先级小的线程仍然有较多的机会执行。
5.6 前台线程和后台线程
线程有两种,默认状况下为前台线程,要想设置为后台线程也很是容易,只须要加一个属性:thread.IsBackground = true;就能够变为一个后台线程了。
重点来了,先后台线程的区别:
A.前台线程:应用程序必须执行完全部的前台线程才能退出;
B.后台线程:应用程序没必要考虑其是否所有完成,能够直接退出。应用程序退出时,自动终止后台线程。
下面咱们使用一个输出从0到1000的数字,来实验一下前台线程和后台线程的区别:
Thread myThread = new Thread(() =>{for (int i = 0; i < 1000; i++)Console.WriteLine(i);}); var key = Console.ReadLine(); if (key == "1") { myThread.IsBackground = true; myThread.Start(); } else { myThread.IsBackground = false; myThread.Start(); }
当咱们在控制台等级输入的时候,
若是输入1(后台线程),线程会很快关闭,并不会等输出完1000个数字再关闭;
若是输入其它,回车后,则线程会等1000个数字输出完后,窗口关闭;
6. 本节要点:
A.本节主要介绍了线程的基本知识;
B.Thread经常使用的属性、方法;
C.Thread委托的方法有多个参数的用法;
D.Thread的优先级;
E.Thread的执行状态;
F.前台线程和后台线程;
后面会继续深刻介绍利用线程提升程序性能。
==============================================================================================
<若是对你有帮助,记得点一下推荐哦,若有有不明白或错误之处,请多交流>
<对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》>
<转载声明:技术须要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>
==============================================================================================