一、进程
-
概念:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础
-
进程之间可以相互独立运行、互不干扰,也可以相互访问、操作
二、线程
-
概念:操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
-
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程
三、多线程的语法
-
类:Thread
-
引用命名空间:using System.Threading;
-
声明一个新线程:Thread 线程名 = new Thread();
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadMethod1);
}
static void threadMethod1()
{
Console.WriteLine("线程1的逻辑...");
}
}
}
- 启动线程:线程名.Start();
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadMethod1);
// 启动线程
t1.Start();
}
static void threadMethod1()
{
Console.WriteLine("运行线程1的逻辑...");
}
}
}
- 设置为后台线程:线程名.IsBackground = true;
(1)当所有前台线程结束的时候,整个程序就结束了。无论是否还有后台线程在运行。
(2)后台线程会随着应用程序进程的终止而终止
(3)如果不设置为后台线程,可能导致进程无法正常关闭
(4)若线程1无限循环:
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadMethod1);
// 启动线程
t1.Start();
}
static void threadMethod1()
{
while (true) {
Console.WriteLine("运行线程1的逻辑...");
}
}
}
}
运行结果如下:(无限循环执行)

(5)设置线程1为后台线程:
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadMethod1);
// 启动线程
t1.Start();
// 设置为后台线程
t1.IsBackground = true;
for (int i = 0; i < 10; ++i) {
Console.WriteLine("运行主线程的逻辑...");
}
}
static void threadMethod1()
{
while (true) {
Console.WriteLine("运行线程1的逻辑...");
}
}
}
}
运行结果如下:(主线程结束后线程1也结束)

- 释放线程:
(1)如果开启的线程不是死循环,不需要刻意去关闭
(2)如果开启的线程是死循环,有两种关闭方式:
①设置bool标识
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
static bool isRuning = true;
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadMethod1);
// 启动线程
t1.Start();
// 设置为后台线程
t1.IsBackground = true;
for (int i = 0; i < 10; ++i) {
Console.WriteLine("运行主线程的逻辑...");
}
// 释放线程
// 1.设置bool标识
isRuning = false;
}
static void threadMethod1()
{
while (isRuning) {
Console.WriteLine("运行线程1的逻辑...");
}
}
}
}
运行结果如下:

②调用线程提供的Abort方法
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
// static bool isRuning = true;
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadMethod1);
// 启动线程
t1.Start();
// 设置为后台线程
t1.IsBackground = true;
for (int i = 0; i < 10; ++i) {
Console.WriteLine("运行主线程的逻辑...");
}
// 释放线程
// 1.设置bool标识
// isRuning = false;
// 2.使用线程的Abort方法
t1.Abort();
}
static void threadMethod1()
{
while (true) {
Console.WriteLine("运行线程1的逻辑...");
}
}
}
}
运行结果同上。
注意:在.Net core版本中无法中止,会发生报错
- 休眠线程:Thread.Sleep();
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
// static bool isRuning = true;
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadMethod1);
// 启动线程
t1.Start();
// 设置为后台线程
t1.IsBackground = true;
for (int i = 0; i < 10; ++i) {
Console.WriteLine("运行主线程的逻辑...");
}
// 释放线程
// 1.设置bool标识
// isRuning = false;
// 2.使用线程的Abort方法
t1.Abort();
// 休眠线程
// 在哪个函数中调用,就使哪个线程休眠
Thread.Sleep(1000); // 使线程休眠1000毫秒 1秒=1000毫秒
}
static void threadMethod1()
{
while (true) {
Console.WriteLine("运行线程1的逻辑...");
}
}
}
}
四、线程之间共享数据
-
多个线程之间使用的内存使共享的,都属于应用程序(进程)
-
要注意:当多线程同时操作同一片内存区域时可能会出问题,但是可以通过加锁的形式避免
-
关键字:lock
-
作用:在多个线程想要访问相同的内存时,实现共享资源的安全访问
-
语法:
lock(引用类型对象){
// 代码块
}
- 实现:在(0,0)处绘制一个红色的圆形、在(10,5)处绘制一个黄色的正方形
代码:
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
// static bool isRuning = true;
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadDrawCir);
Thread t2 = new Thread(threadDrawRec);
// 启动线程
t1.Start();
t2.Start();
// 设置为后台线程
t1.IsBackground = true;
t2.IsBackground = true;
// 释放线程
// 1.设置bool标识
// isRuning = false;
// 2.使用线程的Abort方法
// t1.Abort();
// 休眠线程
// 在哪个函数中调用,就使哪个线程休眠
// Thread.Sleep(1000); // 使线程休眠1000毫秒 1秒=1000毫秒
// 等待按键后结束前台进程
Console.ReadKey();
}
static void threadDrawCir() // 在(0,0)处绘制一个红色的圆形
{
while (true) {
Console.SetCursorPosition(0, 0);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("●");
}
}
static void threadDrawRec() // 在(10,5)处绘制一个黄色的正方形
{
while (true) {
Console.SetCursorPosition(10, 5);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("■");
}
}
}
}
运行结果如下;

出现该结果的原因是:因为两个线程是同时运行的,所以当在(0,0)处绘制一个红色的圆形后,没有将光标设置为(10,5),直接从绘制黄色的正方形开始运行。同理,在(10,5)处绘制一个黄色的正方形后,没有将光标设置为(0,0),直接从绘制红色的圆形开始运行。所以会出现上面的效果。
- 使用互斥锁:
cs
using System;
using System.Threading;
namespace Multithreading
{
class Program
{
// static bool isRuning = true;
static object lockObj = new object(); // 创建一个互斥锁对象
static void Main(string[] args)
{
// 声明一个新线程
// 注意:线程执行的代码需要封装到一个新函数中
Thread t1 = new Thread(threadDrawCir);
Thread t2 = new Thread(threadDrawRec);
// 启动线程
t1.Start();
t2.Start();
// 设置为后台线程
t1.IsBackground = true;
t2.IsBackground = true;
// 释放线程
// 1.设置bool标识
// isRuning = false;
// 2.使用线程的Abort方法
// t1.Abort();
// 休眠线程
// 在哪个函数中调用,就使哪个线程休眠
// Thread.Sleep(1000); // 使线程休眠1000毫秒 1秒=1000毫秒
// 等待按键后结束前台进程
Console.ReadKey();
}
static void threadDrawCir() // 在(0,0)处绘制一个红色的圆形
{
while (true) {
lock (lockObj) { // 使用互斥锁
Console.SetCursorPosition(0, 0);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("●");
}
}
}
static void threadDrawRec() // 在(10,5)处绘制一个黄色的正方形
{
while (true) {
lock (lockObj) { // 使用互斥锁
Console.SetCursorPosition(10, 5);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("■");
}
}
}
}
}
运行结果如下;

- 解释:访问lock中的代码块,会给该引用类型对象上锁;直到运行完所有lock代码块中的代码时,该引用类型对象才会解锁。在其他线程想要使用该引用对象时,若该对象已经上锁,则必须等待该对象解锁后才能继续运行。
五、多线程的意义
使用多线程专门处理一些复杂耗时的逻辑:比如寻路、网络通信等
今天的学习就到这里了。感谢阅读。
再见!