1.线程状态
2.自旋
3.线程暂停
4.线程返回结果
5.取消线程
6.线程捕获异常
1.线程状态
csharp
复制代码
a.定义线程但未启动时, 线程状态: "UnStarted"
b.运行时线程状态: "Running"
c.线程被阻塞(可能是Sleep, Join, 请求锁时), 线程状态: "WaitSleepJoin"; 一旦线程处于此状态时, 线程调度器将线程
踢出
d.线程处于停止状态: "Stop"
2.自旋
csharp
复制代码
你和朋友约定在某个地点见面, 但你不知道朋友什么时候到; 你有两种策略:
a.站在原地, 不停地四处张望, 看看朋友有没有来, 这就是自旋
b.坐在旁边的长椅上, 闭上眼睛休息, 每隔一段时间(比如5分钟)睁开眼睛看一下, 这就是睡眠等待(Sleep)
csharp
复制代码
自旋等待(Spinning)的伪代码
while (条件不满足) {
// 什么也不做, 或者执行一些空操作(比如执行一些特殊的CPU指令, 如pause)
}
这个循环会一直执行, 直到条件满足; 在这个过程中, 线程不会被挂起, 它一直占用着CPU
csharp
复制代码
为什么需要自旋呢?
因为线程的睡眠和唤醒(即上下文切换)是有开销的, 如果等待的时间非常短, 那么让线程睡眠再唤醒的总开销可能比自旋等待
的开销还要大; "自旋适用于等待时间非常短的场景"
但是, 自旋有一个很大的缺点: 如果等待时间很长, 那么自旋就会浪费大量的CPU时间, 因为线程一直在占用CPU做无用的检
查
3.线程暂停
csharp
复制代码
1).Thread.Sleep
a.作用: 让当前线程休眠指定的时间, 期间线程会让出CPU, 进入等待状态, 允许其他线程允许
b.特点:
- 休眠期间线程处于"阻塞状态", 不消耗CPU资源
- 休眠时间到了, 线程就进入就绪状态, 等待调度
- 由于上下文切换, 可能会有一定的开销
c.示例
csharp
复制代码
2).Thread.SpinWait
a.作用: 让当前线程进行自旋等待, 线程不会让出CPU, 而是在一个循环中不断检查条件(忙等待)
b.特点:
- 参数iterations是自旋的次数
- 自旋期间线程不会放弃CPU, 因此不涉及上下文切换, 但浪费CPU周期
- 适用于等待时间极短的情况
c.示例
csharp
复制代码
3).SpainWait.SpainUntil
a.作用: 自旋等待直到某个条件成立或超时
b.特点:
- 在条件满足或超时之前, 会混合使用自旋和真正的休眠(以减少CPU占用)
- 返回值为true表示条件在超时前满足, 否则为false
- 适用于条件可能在短时间内满足的等待场景
4.线程返回结果
csharp
复制代码
Thread中无内置的方法返回结果, 返回结果的唯一方法是共享变量
csharp
复制代码
class Program
{
private static string result;
static void Main(string[] args)
{
Thread thread = new Thread(() => {
Worker();
});
thread.Start();
thread.Join();
Console.WriteLine(result);
}
private static void Worker()
{
result = "Show Result";
}
}
5.取消线程
csharp
复制代码
1).通过一个共享变量来取消线程
volatile 的好处: "让线程之间看得见彼此对变量的修改,并且不乱排顺序,性能接近普通变量但比锁快得多"
csharp
复制代码
class Program
{
// 控制线程是否被取消
// volatile 保证线程从内存中读取最新的值
// 适用于一个线程写 一个线程读
private static volatile bool cancelThread;
static void Main(string[] args)
{
Thread thread = new Thread(() => {
Worker();
});
thread.Start();
Console.ReadLine();
cancelThread = true;
}
private static void Worker()
{
while (cancelThread)
{
Thread.Sleep(1000);
}
}
}
csharp
复制代码
2).CancellationToken 来取消任务
csharp
复制代码
class Program
{
private static CancellationTokenSource cts = new CancellationTokenSource();
static void Main(string[] args)
{
Thread thread = new Thread(() => Worker(cts.Token));
thread.Start();
Console.ReadLine();
cts.Cancel(); // 发送取消信号
thread.Join();
}
private static void Worker(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("Working...");
Thread.Sleep(1000);
}
}
}
6.线程捕获异常
csharp
复制代码
a."工作线程出现异常, 不会传播到调用线程"
比如: 主线程中启动工作线程, 工作线程出现异常, 主线程无法捕获
b.处理线程的异常, 则需在线程内使用try catch即可
csharp
复制代码
Thread thread = new Thread(() =>
{
try
{
// 工作代码
}
catch (Exception ex)
{
// 处理异常
Console.WriteLine($"线程异常:{ex.Message}");
// 考虑如何通知主线程
}
finally
{
// 清理资源
}
});
thread.Start();