You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

for循环生成后台线程时的异常行为问题咨询

闭包捕获循环变量导致的线程行为异常

先看你给出的测试代码:

Thread thread;
for (int i = 6000; i < 6006; i++) {
    //Thread.Sleep(1);
    thread = new Thread(() => derp(i));
    thread.IsBackground = true;
    thread.Start();
}
private void derp(int a) {
    MessageBox.Show(a.ToString());
}

为什么不加Thread.Sleep(1)会行为异常?

这是C#里闭包捕获循环变量的经典陷阱:你的lambda表达式() => derp(i)捕获的是循环变量i的引用,而不是每次循环时i的具体值。

当循环快速执行时,线程的启动速度远远赶不上循环的迭代速度——循环已经把i从6000递增到6006了,那些线程才陆续开始执行。此时所有线程访问的都是同一个i变量的最终值6006,所以你会看到弹出的都是6006的消息框,完全不符合预期。

为什么加了Thread.Sleep(1)就正常了?

加了Sleep之后,每次循环都会暂停1毫秒,给当前创建的线程足够的时间启动并执行derp(i)。这时候线程在i递增到下一个值之前,就已经捕获到了当前循环迭代的i值,所以能正确显示6000到6005。

不过这种解决方法是依赖时间的临时hack,非常不可靠——如果系统负载高、线程启动延迟,问题还是会复现。

正确的解决方案:捕获临时变量

在循环内部创建一个临时变量,把当前i的值赋值给它,让lambda捕获这个临时变量,这样每个线程都会拿到独立的、对应迭代的值:

Thread thread;
for (int i = 6000; i < 6006; i++) {
    int temp = i; // 创建临时变量保存当前i的值
    thread = new Thread(() => derp(temp));
    thread.IsBackground = true;
    thread.Start();
}
private void derp(int a) {
    MessageBox.Show(a.ToString());
}

如果你使用的是C# 5及以上版本,也可以改用foreach循环(C# 5对foreach的变量捕获做了优化,每次迭代都会创建新的变量),不过for循环没有这个优化,还是需要通过临时变量来解决。

内容的提问来源于stack exchange,提问作者Ayy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:28:11