前言
多线程编程是跨语言的,跨环境的,所以我们得学好它,对应用程序的性能提高是有帮助的。
阅读目录
一:System.Threading
二:Thread类
三:Thread说明
四:Thread的使用
五:运行机制
六:运行效果
一:System.Threading
提供一些使得可以进行多线程编程的类和接口,此命名空间包括管理线程组的ThreadPool类,可以在指定的时间后调用委托的Timer类,用于同步互斥线程的Mutex类。
二:Thread类
1. 启动新的线程
Thread thread = new Thread(new ThreadStart(Count));Count是要被新的线程执行的函数,这个函数默认情况下是没有参数的
2. 杀死线程
在杀死一个线程前,先判断这个线程是否还活着(用IsAlive属性),如果它已经死掉了,就不要在杀死它了,那就成鞭尸了没有用的,如果它活着调用ABort方法来杀死此线程。
3. 暂停线程
让一个运行的线程暂时停止运行即让一个正常运行的线程休眠一段时间,如:thread.sheep(1000)即让此线程休眠1秒钟
4. 优先级
每个线程是不一样的,它有优先级的,Thread 类中的ThreadPriority属性用来设置优先级,但是不能保证操作系统会接受此优先级,一个线程的优先级分为五种,Normal(正常的),AboveNormal(超过正常的),BelowNormal(低于正常的),Highest(最高的),Lowest(最低的)。
5. 挂起线程
挂起线程是整个线程暂时停止了,挂起线程的整个暂停和暂停一个线程不一样,暂停一个线程是让一个正常运行的线程休眠一段时间,而挂起线程是把机子挂起来了,Thread类的Suspend方法用来挂起线程,直到调用Resume,此线程才能继续执行,如果线程被挂起了,当然就不会起作用了。
举个例子
比如你要抄腊肉,暂停线程相当于休息一会再炒腊肉,挂起线程就是把腊肉挂到墙上了,没得抄了,恢复线程相当于把墙上的腊肉拿下来炒了。
6. 恢复线程
Resume用来恢复已经挂起的线程,让它继续执行,如果线程没被挂起,当然也不会起作用了。
举个例子
比如我控制5个机器人去探索月球,每个机器人相当于一个线程,每个机器人头上有4个按钮(启动新的线程,暂停线程,挂起线程,恢复线程),我按一下启动新的线程按钮,这个机器人就开始工作了,我按一下暂停线程,机器人就停止工作了,这5个机器人相当于5个线程,同时并发执行探索月球的,你可以通过每个机器人头上的按钮,同时控制这5个机器人也相当于同时控制5个线程了。
三:Thread说明
1. 一个线程的方法是不带任何参数的,同时也不返回任何值的,它的命名规则和一般方法一样,可以是静态方法,也可以是非静态的方法,当这个方法执行完毕后,相应的线程也就结束了,这个线程的IsAlive属性也就被设置为flase了。
2. .NET的公共语言运行时(CLR)能区分两种不同类型的线程:即前台线程和后台线程,两者的区别是前台线程是应用程序必须运行完所有的前台线程才能退出,而对于后台线程而言,应用程序不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出后,就都自动结束了。
默认情况下都是前台线程 IsBackground = false。
四:Thread的使用
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace _1_ThreadClassExample
{
class Program
{
public static void ThreadProcess()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("ThreadProcess: {0}", i);
//阻塞当前的线程thread1,执行别的进程也就是Main这个进程,线程被阻塞的毫秒数为0则表示应挂起此线程(也就是thread1这个线程)以便其他等待线程能够执行(也就是Main这个进程)
Thread.Sleep(0);
}
}
static void Main(string[] args)
{
Console.WriteLine("在主进程Main中启动一个线程");
//创建一个线程
Thread thread1 = new Thread(new ThreadStart(ThreadProcess));
//启动此线程
thread1.Start();
//创建一个线程
Thread thread2 = new Thread(new ThreadStart(ThreadProcess));
//启动此线程
thread2.Start();
//挂起此线程
thread2.Suspend();
for (int i = 0; i < 4; i++)
{
Console.WriteLine("主进程Main输出.....");
//阻塞当前的主进程Main,执行别的进程也就是thread1这个线程,线程被阻塞的毫秒数为0则表示应挂起此线程(也就是Main这个进程)以便其他等待线程能够执行(也就是thread1这个线程)
Thread.Sleep(0);
}
Console.WriteLine("主线程Main调用线程Join方法直到thread1线程结束");
//阻塞调用线程,直到某个线程终止时为止,也就是说阻塞主进程Main,直到thread1线程执行完毕
thread1.Join();
Console.WriteLine("thread1线程结束");
thread2.Resume();//恢复挂起的线程
//thread2.IsBackground = true;
}
}
}
五:运行机制
在最开始输出了“主进程Main输出......”,紧跟着输出了“ThreadProcess:1” ,又接着输出了“主进程Main输出......”,然后紧跟着是“ThreadProcess:2””,又接着输出了“主进程Main输出......”,然后紧跟着是“ThreadProcess:3””,它们交替出现,这是因为在for (int i = 0; i < 4; i++)中有句Thread.Sleep(0);的缘故,它的意思阻塞当前的主进程也就是Main这个主线程,执行别的进程,这个别的进程指的是thread1这个线程也就是ThreadProcess()这个函数,在ThreadProcess()这个函数中也有句Thread.Sleep(0);它的意思同样也是阻塞当前的进程也就是thread1这个线程,执行别的进程,这里别的线程指的是Main这个主线程,所以它俩会交替出现,因为thread2这个线程被挂起了,所以暂时是不会被执行的,因为这个线程(腊肠)被挂到墙上了,只有我们恢复这个线程(也就是从墙上取下这个腊肠才能炒它),这个线程才会执行的,thread1.Join();的意思是阻塞调用线程,直到某个线程终止时为止,什么意思呢就是阻塞当前的主进程就是Main这个主进程,直到调用的线程也就是thread1这个线程执行完毕,所以你会看到连着输出了“ThreadProcess:4”,“ThreadProcess:5”,,“ThreadProcess:6”等等直到,“ThreadProcess:9”结束,紧接着我们写句thread2.Resume();恢复挂起的thread2这个线程,因为thread2这个线程执行的也是ThreadProcess()这个函数,所以最后你会看到连着输出了“ThreadProcess:1”,“ThreadProcess:2”,“ThreadProcess:3”等等直到,“ThreadProcess:9”,结束,因为默认thread2.IsBackground = false;,也就是说thread2是前台线程,前台线程的特点是主进程必须等到线程执行完毕后才能结束,所以输出“ThreadProcess:1”,“ThreadProcess:2”,“ThreadProcess:3”等等直到9,我们在更改代码为thread2.IsBackground = true;虽然我们恢复了thread2这个线程,但是因为thread2.IsBackground = true,也就是说thread2是后台线程,后台线程的特点是主进程不等线程执行完毕就结束了,所以没有输出“ThreadProcess:1”,“ThreadProcess:2”,“ThreadProcess:3”等等直到9,主进程就自己结束了
六:运行效果
thread2.IsBackground = true;
thread2.IsBackground = false;