一、线程(Thread)介绍
1.1 线程的基本概念
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位 。
在 C# 程序里,一个进程默认会有一个主线程,我们也可以手动创建多个子线程,让它们并行(或并发)执行不同任务,比如同时进行文件下载、数据处理、界面渲染等操作,提升程序整体运行效率。
1.2 线程的应用场景
- 后台任务处理:像应用程序启动时加载配置文件、定期清理临时文件等,可通过后台线程执行,避免阻塞主线程,保证界面交互流畅。
- 并行计算:处理大规模数据运算(如数组排序、图像像素处理)时,利用多线程并行计算,充分发挥 CPU 多核优势,缩短运算时间。
- 网络通信:服务器程序中,为每个客户端连接创建独立线程处理请求,实现同时服务多个客户端;客户端也可通过线程异步发起网络请求,不影响其他操作。
1.3 线程的生命周期
线程是轻量级进程。每个线程都定义了一个独特的控制流。线程的生命周期始于 System.Threading.Thread 类的对象创建,终于线程终止或执行完成。
以下是线程生命周期中的各种状态 −
1.未启动状态
线程实例已创建,但 Start 方法尚未调用。
2.就绪状态
线程已准备好运行,正在等待 CPU 周期。
3.不可运行状态
以下情况线程不可执行:
调用了 Sleep 方法
调用了 Wait 方法
被 I/O 操作阻塞
4.死亡状态
线程完成时的状态执行或中止。
二、线程基础
2.1 线程的创建
在 C# 中,可通过 System.Threading.Thread 类创建线程。示例如下:
static void Main()
{
// 创建无参数线程
Thread thread1 = new Thread(DoWork);
thread1.Start();
// 创建带参数线程
Thread thread2 = new Thread(DoWorkWithParam);
thread2.Start("Hello, Thread!");
Console.WriteLine("主线程继续执行...");
Console.ReadLine();
}
static void DoWork()
{
Console.WriteLine("线程 1 执行任务");
}
static void DoWorkWithParam(object param)
{
Console.WriteLine($"线程 2 收到参数:{param},执行任务");
}
当然,我们也能够使用委托和lambda表达式的方法,来创建线程实例。示例如下
static void Main(string[] args)
{
object obj = "Hello, Thread!";
//第一种写法
Thread thread = new Thread(DoWorkWithParam);
thread.Start(obj);
//第二种写法 delegate
Thread thread1 = new Thread(new ParameterizedThreadStart(DoWorkWithParam));
thread1.Start(obj);
//第三种写法 lambda
Thread thread2 = new Thread((arg) => { DoWorkWithParam(arg); });
thread2.Start(obj);
}
注意:
可传参的写法 注意参数类型必须为object.
2.2 线程的常用属性
以下是整理后的 Thread 常用属性速查表(C#)
Thread 常用属性速查表
| 属性名称 | 类型 | 作用 |
|---|---|---|
| ApartmentState | ApartmentState | 获取或设置线程的单元状态(STA/MTA/Unknown),影响 COM 交互。 |
| CurrentCulture | CultureInfo | 获取或设置当前线程的区域性,控制日期、数字等格式化规则。 |
| CurrentPrincipal | IPrincipal | 获取或设置线程的安全负责人,用于基于角色的权限检查。 |
| CurrentThread | Thread | 静态属性,获取当前正在执行的线程对象引用。 |
| CurrentUICulture | CultureInfo | 获取或设置资源管理器使用的区域性,影响本地化资源加载。 |
| ExecutionContext | ExecutionContext | 获取线程的上下文信息(安全、调用逻辑等)。 |
| IsAlive | bool | 返回线程是否已启动且未终止(true/false)。 |
| IsBackground | bool | 获取或设置线程是否为后台线程(后台线程不影响进程退出)。 |
| IsThreadPoolThread | bool | 返回线程是否属于托管线程池(true/false)。 |
| ManagedThreadId | int | 获取托管线程的唯一标识符(只读)。 |
| Name | string | 获取或设置线程名称(调试时标识线程)。 |
| Priority | ThreadPriority | 获取或设置线程调度优先级(Highest/Normal/Lowest 等)。 |
| ThreadState | ThreadState | 返回线程当前状态枚举(Running、WaitSleepJoin 等)。 |
部分属性使用示例如下:
Thread workerThread = new Thread(() =>
{
Console.WriteLine("线程执行中...");
Thread.Sleep(2000);
});
workerThread.Name = "后台工作线程"; // 设置线程名称
workerThread.Start();
Console.WriteLine($"线程名称: {workerThread.Name}");
Console.WriteLine($"线程状态: {workerThread.ThreadState}"); // 输出状态如Running/WaitSleepJoin
注意事项
线程的优先级并不是绝对的运行优先级,而是占比优先(概率大)
2.3 线程的常用方法
线程操作方法
| 方法名称 | 作用描述 | 注意事项 |
|---|---|---|
Thread.Start() | 启动线程的执行,使其进入就绪状态并等待CPU调度 | 只能对未启动的线程调用,重复调用会抛出异常 |
Thread.Suspend() | 挂起线程执行(暂停),若线程已挂起则无效果 | .NET Core/.NET 5+已弃用,可能造成死锁或资源泄漏 |
Thread.Resume() | 恢复被挂起的线程 | .NET Core/.NET 5+已弃用,需与Suspend()配对使用 |
Thread.Interrupt() | 中断处于等待状态(Wait/Sleep/Join)的线程,抛出ThreadInterruptedException异常 | 对运行状态的线程无效,需捕获异常处理 |
Thread.Join() | 阻塞当前线程,直到目标线程执行完毕 | 可设置超时时间,避免永久阻塞 |
Thread.Sleep() | 使当前线程暂停指定毫秒数,释放CPU时间片 | 静态方法,精度受系统时钟影响 |
Thread.Abort() | 强制终止线程(通过抛出ThreadAbortException),不保证立即停止 | .NET Core/.NET 5+已移除,可能破坏程序状态,已过时,慎用 |
三、线程的内存原理
3.1 线程栈
每个线程都有自己独立的线程栈,用于存储局部变量、方法参数、返回地址等临时数据 。栈的内存空间是连续的,由操作系统自动管理分配和释放。比如在一个线程的方法中定义局部变量 int num = 10;,num 就会被存储在该线程的栈中。线程栈的大小一般是固定的(可在创建线程时设置,如 new Thread(...) { StackSize = 1024 * 100 }; ,单位为字节 ),若线程中局部变量过多、递归深度过大,可能导致栈溢出。
3.2 共享内存与线程同步

进程的堆内存、静态变量等是线程间共享的 。多个线程同时访问、修改共享资源时,就会出现线程安全问题,比如多个线程同时对一个静态变量 count 进行自增操作或者是文件的操作时:
static int count = 0;
static void IncrementCount()
{
for (int i = 0; i < 1000; i++)
{
count++;
// 实际是 count = count + 1,可能出现线程交错,导致结果不准确
}
}
这时需要通过线程同步机制(如锁 lock、Monitor、Mutex 等 )来保证共享资源访问的原子性,避免数据竞争。
static object lockObj = new object();
static int count = 0;
static void IncrementCount()
{
for (int i = 0; i < 1000; i++)
{
lock (lockObj)
{
count++;
}
}
}
lock 内部借助 Monitor 实现,能确保同一时间只有一个线程进入临界区(lock 包裹的代码块 )访问共享资源。
四、总结
-
线程数量控制:
-
CPU密集型任务:线程数 ≈ 处理器核心数
-
I/O密集型任务:可适当增加线程数
-
-
同步机制选择:
-
简单场景:lock关键字
-
读写分离:ReaderWriterLockSlim
-
-
避免常见陷阱:
-
避免过度同步(锁粒度过粗)
-
防止死锁(按固定顺序获取锁)
-
C# 线程是实现多任务并发的关键工具,理解其基础概念、内存原理,熟练运用创建、控制线程的方法和属性,处理好线程同步问题,能让程序在性能、响应性上更出色 。但线程也并非越多越好,过多线程会带来线程上下文切换开销、资源竞争加剧等问题,实际开发中需结合场景合理设计线程模型,平衡性能与复杂度,让多线程编程真正成为提升程序质量的助力。
1642

被折叠的 条评论
为什么被折叠?



