一、线程优先级(ThreadPriority)
1. 核心原理
CPU 采用时间片轮转调度机制,线程优先级不决定执行先后顺序 ,只决定:获取CPU时间片的概率、执行频率、占用时长。
优先级从高到低排序:Highest > AboveNormal > Normal(默认) > BelowNormal > Lowest
高优先级线程:更容易抢到CPU资源、执行频次更高;低优先级线程:大概率礼让,偶尔执行。
2. 独立完整代码
cs
private void button1_Click(object sender, EventArgs e)
{
// 正常优先级
Thread t1 = new Thread(ShowThreadInfo);
t1.Name = "线程1-Normal";
t1.Priority = ThreadPriority.Normal;
// 最低优先级
Thread t2 = new Thread(ShowThreadInfo);
t2.Name = "线程2-Lowest";
t2.Priority = ThreadPriority.Lowest;
// 最高优先级
Thread t3 = new Thread(ShowThreadInfo);
t3.Name = "线程3-Highest";
t3.Priority = ThreadPriority.Highest;
// 低于正常优先级
Thread t4 = new Thread(ShowThreadInfo);
t4.Name = "线程4-BelowNormal";
t4.Priority = ThreadPriority.BelowNormal;
// 高于正常优先级
Thread t5 = new Thread(ShowThreadInfo);
t5.Name = "线程5-AboveNormal";
t5.Priority = ThreadPriority.AboveNormal;
// 统一启动,并发抢占CPU
t1.Start();
t2.Start();
t3.Start();
t4.Start();
t5.Start();
}
// 线程执行方法:打印线程信息
public void ShowThreadInfo()
{
for (int i = 0; i < 10000; i++)
{
Console.WriteLine($"线程名:{Thread.CurrentThread.Name},ID:{Thread.CurrentThread.ManagedThreadId},状态:{Thread.CurrentThread.ThreadState}");
}
}
3. 专属注意事项
-
优先级不保证绝对先后执行,只是概率倾斜,低优先级线程也可能先执行
-
默认线程优先级为 Normal,日常业务无需手动修改
-
禁止滥用最高优先级,容易抢占系统资源,导致系统卡顿
-
优先级仅作用于同进程内线程,无法跨进程抢占CPU
二、线程传入多个委托方法(多任务封装)
1. 核心原理
利用 Action 委托封装多个无参无返回值的耗时任务,将两个自定义方法传入同一个子线程执行,实现代码复用、任务封装。子线程内顺序执行多个委托任务,通过 Invoke 安全更新UI。
2. 独立完整代码
cs
private void button2_Click(object sender, EventArgs e)
{
// 传入两个自定义耗时任务
RunTwoTask(
// 任务1:计算求和,更新label1
() =>
{
int sum = 0;
for (int i = 0; i < 10000; i++)
sum += i;
// 跨线程安全更新UI
Invoke(new Action(() => label1.Text = sum.ToString()));
},
// 任务2:计算求和,更新label2
() =>
{
int sum = 0;
for (int i = 0; i < 10000; i++)
sum += i;
Invoke(new Action(() => label2.Text = sum.ToString()));
}
);
}
// 封装方法:接收两个委托,在子线程执行
public void RunTwoTask(Action task1, Action task2)
{
Thread t = new Thread(() =>
{
task1.Invoke();
task2.Invoke();
});
t.Start();
Console.WriteLine("主线程不阻塞,直接执行完毕");
}
3. 专属注意事项
-
多个委托在同一个子线程串行执行,不是并发执行
-
子线程严禁直接操作UI,必须使用 Invoke 抛回主线程更新
-
Action 委托仅支持无参无返回值方法,有参数/返回值需使用 Func
-
该写法适合批量封装耗时任务,简化线程创建代码
三、lock 线程锁(解决多线程资源争抢)
1. 核心原理
多线程同时操作同一个共享变量/资源 时,会出现数据错乱、数据覆盖问题。lock(锁对象) 可以锁住代码块,同一时间仅允许一个线程进入执行,其他线程排队等待,保证共享资源操作的原子性、安全性。
2. 独立完整代码
cs
// 共享全局变量(多线程争抢资源)
int sum = 0;
// 专属锁对象(必须唯一、静态、只读)
readonly object lockObj = new object();
private void button3_Click(object sender, EventArgs e)
{
// 启动两个线程同时操作sum
Thread t1 = new Thread(AddSum);
Thread t2 = new Thread(SubSum);
t1.Start();
t2.Start();
}
// 线程1:累加操作
public void AddSum()
{
for (int i = 0; i < 10000; i++)
{
// 锁定代码块:单线程独占执行
lock (lockObj)
{
sum++;
Console.WriteLine($"线程1执行:sum = {sum}");
}
}
}
// 线程2:累加操作
public void SubSum()
{
for (int i = 0; i < 10000; i++)
{
// 同一把锁,排队执行
lock (lockObj)
{
sum++;
Console.WriteLine($"线程2执行:sum = {sum}");
}
}
}
3. 专属注意事项
-
锁对象必须是全局唯一,不能在方法内new,否则锁失效
-
多个线程必须使用同一把锁,不同锁无法互斥
-
lock 只锁代码块,不锁对象,仅限制多线程进入
-
锁范围尽量最小化,避免锁过多代码导致性能卡顿、变回同步
-
无锁:数据错乱;有锁:数据安全、有序执行
四、线程死锁(成因、代码、解决方案)
1. 核心原理
死锁成因:两个或多个线程,互相持有对方需要的锁资源,同时互相等待对方释放锁,双方僵持不释放,线程永久阻塞,程序卡死。
经典场景:
-
线程1:持有锁A,等待锁B
-
线程2:持有锁B,等待锁A
-
双方无限等待,代码永久卡住
2. 死锁错误代码(可直接复现卡死)
cs
private void button4_Click(object sender, EventArgs e)
{
object lockA = new object();
object lockB = new object();
// 线程1:先拿A锁,再拿B锁
new Thread(() =>
{
lock (lockA)
{
Thread.Sleep(100); // 保证线程2先拿到B锁
lock (lockB)
{
Console.WriteLine("线程1执行完成");
}
}
}).Start();
// 线程2:先拿B锁,再拿A锁
new Thread(() =>
{
lock (lockB)
{
Thread.Sleep(100); // 保证线程1先拿到A锁
lock (lockA)
{
Console.WriteLine("线程2执行完成");
}
}
}).Start();
}
3. 死锁最优解决方案
统一锁的获取顺序:所有线程获取多把锁的顺序保持一致,从根源杜绝死锁。
4. 修正后无死锁代码
cs
private void button4_Click(object sender, EventArgs e)
{
object lockA = new object();
object lockB = new object();
// 线程1:固定顺序 先A后B
new Thread(() =>
{
lock (lockA)
{
Thread.Sleep(100);
lock (lockB)
{
Console.WriteLine("线程1执行完成");
}
}
}).Start();
// 线程2:和线程1保持一致 先A后B
new Thread(() =>
{
lock (lockA)
{
Thread.Sleep(100);
lock (lockB)
{
Console.WriteLine("线程2执行完成");
}
}
}).Start();
}
5. 专属注意事项
-
死锁四大必要条件:互斥、请求保持、不可剥夺、循环等待
-
最简单高效的解决方式:所有线程锁顺序统一
-
禁止多线程交叉嵌套锁,极易引发死锁
-
死锁后线程永久阻塞,不会自动恢复,只能重启程序
五、整体知识点总结
-
一、线程优先级:不控制执行顺序,仅倾斜CPU时间片占用概率
-
二、多委托传参:封装多段耗时逻辑,单线程串行执行,安全更新UI
-
三、lock线程锁:保证共享资源原子操作,解决多线程数据错乱问题
-
四、线程死锁:交叉嵌套锁导致互相等待,统一锁顺序即可彻底解决