一丶概念
1. 进程:进程是操作系统分配处理器时间的基本单元。
● 在进程中可以有多个线程同时执行代码;
● 进程之间相互独立,一个进程无法访问另一个进程的数据。
2. 线程:线程是进程中的基本执行单元,是操作系统分配CPU时间的基本单位。
● 一个进程可以包含多个线程;
● 线程主要由:CPU寄存器、调用栈和线程本地存储器组成。
二丶线程创建
1.创建多线程步骤:
①:编写线程所执行的方法;
②:实例化Thread类,并传入一个指向相乘所执行方法的委托;
③:调用Thread实例的Start方法,标记该线程可以被CPU执行,但是具体时间由CPU决定。
2.基础示例
class Program
{
public static void Main(string[] args)
{
//2:实例化Thread类,并传入一个指向相乘所执行方法的委托
Thread thread1 = new Thread(new ThreadStart(Thread1));
//3:调用Thread实例的Start方法
thread1.Start();
Console.ReadLine();
}
/// <summary>
/// 1:编写线程所执行的方法
/// </summary>
static void Thread1()
{
Console.WriteLine("这是无参方法");
}
}
运行结果:
3.匿名委托和Lambda表达式赋值
public static void Main(string[] args)
{
//通过匿名委托创建
Thread thread1 = new Thread(delegate () { Console.WriteLine("匿名委托"); });
thread1.Start();
//通过Lambda表达式创建
Thread thread2 = new Thread(() => Console.WriteLine("Lambda表达式"));
thread2.Start();
Console.ReadLine();
}
运行结果
4.ParameterizedThreadStart是一个有参的void委托:
class Program
{
public static void Main(string[] args)
{
Thread thread1 = new Thread(new ParameterizedThreadStart(Thread1));
thread1.Start("这是一个有参委托");
Console.ReadLine();
}
static void Thread1(object obj)
{
Console.WriteLine(obj);
}
}
运行结果
注意:ParameterizedThreadStart委托的参数类型必须是Object的。如果使用的是不带参数的委托,不能使用带参数的Start方法运行线程,否则系统会抛错。
三丶线程详解
1.属性
●ManagedThreadId:确认线程的唯一标识符;而Name是个可变值,默认为一个Null;
●Priority:线程执行的优先级别,里面包含5个选项:Lowest、BelowNormal、Normal(默认值)、AboveNormal和Highest;
●ThreadState:可以检测线程状态;
●CurrentThread:获取当前运行的线程。
2.前台线程与后台线程
●前台线程:只有所有的前台线程都结束,应用程序才能结束。默认情况下创建的线程都是前台线程。
●后台线程:只要所有的前台线程结束,后台线程自动结束。
后台线程一般用于处理不重要的事情,应用程序结束时,后台线程执行与否对整个程序没有影响。如果要执行重要的的事情,请务必使用前台线程。
class Program
{
public static void Main(string[] args)
{
BackGroundTest backGround1 = new BackGroundTest(10);
Thread fThread = new Thread(new ThreadStart(backGround1.RunLoop))
{
Name = "前台线程"
};
BackGroundTest backGround2 = new BackGroundTest(20);
Thread bThread = new Thread(new ThreadStart(backGround2.RunLoop))
{
IsBackground = true,
Name = "后台线程"
};
fThread.Start();
bThread.Start();
}
}
class BackGroundTest
{
private readonly int Count;
public BackGroundTest(int count)
{
Count = count;
}
public void RunLoop()
{
string strThreadName = Thread.CurrentThread.Name;
for (int i = 1; i <= Count; i++)
{
Console.WriteLine("{0}计数:{1}", strThreadName, i);
Thread.Sleep(1000);
}
Console.WriteLine("{0}完成计数", strThreadName);
Thread.Sleep(1000);
}
}
运行结果,当fThread进程结束退出时,Main函数就自动结束,后台线程也自动结束。
3.线程同步
所谓同步是指在某一时刻,只有一个线程访问变量。比如火车售票:现在还剩10张票,但是有20个线程都想购买,如果不同步,则会导致20个线程都购买成功。
class Program
{
public static void Main(string[] args)
{
TicketStation ticketStation = new TicketStation();
for (int i = 1; i <= 20; i++)
{
Thread thread = new Thread(new ThreadStart(ticketStation.Sale));
thread.Name = "购票者" + i;
thread.Start();
}
Console.ReadKey();
}
}
class TicketStation
{
public int num = 10;
public void Sale()
{
if (num > 0)
{
Thread.Sleep(1000);
num -= 1;
Console.WriteLine("{0}买了一张票,还剩余{1}张", Thread.CurrentThread.Name, num);
}
else
{
Console.WriteLine("买完了");
}
}
}
结果如图:
从运行结果看出,多个线程访问共享资源,如果不考虑同步问题,结果是不正确的。那怎么来解决同步问题呢?C#中有个关键字lock,可以用来解决同步问题。
class TicketStation
{
public int num = 10;
public void Sale()
{
lock (this)
{
if (num > 0)
{
Thread.Sleep(1000);
num -= 1;
Console.WriteLine("{0}买了一张票,还剩余{1}张", Thread.CurrentThread.Name, num);
}
else
{
Console.WriteLine("不好意思,卖完了!");
}
}
}
}
结果如图:
现在结果正如期望一样,不会出现票卖多了的情况。