C# 多线程编程
一、Thread 基础
进程: 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。
线程: 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数(方法)。
多线程: 多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
二、 多线程
优点:可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。
缺点:线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
多线程需要协调和管理,所以需要CPU时间跟踪线程;
线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
线程太多会导致控制太复杂,最终可能造成很多Bug;
三、控制线程的类和方法
类:using System.Threading; Thread类
Thread类的方法:Start(): 启动线程;
Sleep(int):静态方法,暂停当前线程指定的毫秒数;
Abort(): 通常使用该方法来终止一个线程;
Suspend(): 该方法并不终止未完成的线程,它仅仅挂起线程,以后还可恢复;
Resume(): 恢复被Suspend()方法挂起的线程的执行。
Priority 枚举设置线程的优先级,由高到低 Highest,AboveNormal,Normal,BelowNormal,Lowest;系统默认为ThreadPriority.Normal
在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动的方法。在.NET中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动方式。
1. 不带参数的启动方式
在大型缓存的时候我们会经常会用线程,当前程序去缓存中提取数据,开启另一个线程判断当前的缓存数据是否过期,是否需要从数据库提取最新数据。
定义性别的枚举
/// 姓名枚举
/// </summary>
enum PersonSexTypeEnum
{
Man,
Woman,
}
定义Person 类,成员
{
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 生日月份
/// </summary>
public int BirthMonth { get; set; }
/// <summary>
/// 性别
/// </summary>
public PersonSexTypeEnum sex;
/// <summary>
/// 人
/// </summary>
public Person person { get; set; }
}
Thread
{
static void Main(string[] args)
{
Person p = new Person();
p.Name = "张三";
p.Age = 22;
p.BirthMonth = 12;
p.sex = PersonSexTypeEnum.Man;
System.Threading.Thread thrad = new System.Threading.Thread(new System.Threading.ThreadStart(p.PersonToString));
thrad.Start();
}
}
上面我们实例化 person 类, 使用线程thrad 调用 p.personToString 方法,这个方法在执行完毕后,线程结束, 不要理解为是调用了 thrad. Abort() abort 是停止线程,你看到这里肯定会问,你实例化了Person 给Person 成员都赋值,在线程的方法中不就可以使用了吗? 刚学习C# 的人可能都知道了 。
/// 不带参数
/// </summary>
public void PersonToString()
{
System.Threading.Thread.Sleep(60);
Console.WriteLine("no parameter ");
}
2.这里我们介绍带参数的启动方法
如果要在实例化线程时要带一些参数,就不能用ThreadStart委托作为构造函数的参数来实例化Thread了,而要parameterizedThreadStart委托,和ThreadStart 一样的是也是线程启动时要执行的方法,和ThreadStart不同的是,他在实例化时可以用一个带有object参数的方法作为构造函数的参数,而实例化ThreadStart时所用到得方法是没有参数的。
{
Person p = new Person();
p.Name = "张三";
p.Age = 22;
p.BirthMonth = 12;
p.sex = PersonSexTypeEnum.Man;
//带参数的线程
System.Threading.Thread thradparameter = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(p.PersonToString));
thradparameter.Start(p);
}
带参数的方法
/// 传递一个Object
/// </summary>
/// <param name="obj"></param>
public void PersonToString(object obj)
{
if (obj == null)
return;
if (obj is Person)
{
Person p = obj as Person;
System.Threading.Thread.Sleep(61);
Console.WriteLine("person name " + p.Name + "Age" + p.Age);
}
}