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

For循环中创建带参数Thread时迭代变量j值异常原因排查

循环内启动线程时迭代变量值异常的原因

我在测试一段代码,需要在for循环中重复执行任务,每次循环更新变量。代码如下:

for (int j = 0; j < 6; j++)
{
    _waitNextBatch++;
    Console.WriteLine($"{_waitNextBatch}");

    BatchSensor bs = new BatchSensor { SensorName = $"batch - {j}" };

    new Thread(() => SimulateBS(bs, j)).Start();
}

运行后发现,SimulateBS方法能获取正确的bs对象,但所有线程的迭代变量j要么是循环最后一次的值6,要么是混乱的中间值,比如输出:

batch - 0 | 6
batch - 2 | 6
batch - 5 | 6
batch - 4 | 6
batch - 3 | 6
batch - 1 | 6

或者:

batch - 0 | 2
batch - 1 | 3
batch - 2 | 3
batch - 3 | 5
batch - 4 | 5
batch - 5 | 6

核心原因:闭包捕获的是变量引用,而非当前值

  • 代码中的lambda表达式() => SimulateBS(bs, j)捕获的是迭代变量j的引用,而非创建线程那一刻j的具体数值。整个for循环里,j是同一个变量,每次循环只是更新它的取值。
  • for循环的执行速度远快于线程的启动和初始化,当线程真正开始执行SimulateBS时,循环可能已经完成了多次迭代,甚至直接走到了循环结束后的j=6(因为循环条件是j<6,最后一次循环后j会自增到6)。
  • 这就导致线程读取到的j是它执行瞬间变量的当前值,而非创建线程时的数值,所以会出现要么全是6,要么是混乱中间值的情况。

为什么bs能获取正确值?

因为每次循环内部都新建了BatchSensor bs = new BatchSensor { ... },每个线程捕获的是当前循环中新建的bs对象的引用。每个循环的bs都是独立实例,不会被后续循环的赋值覆盖,所以每个线程能拿到对应循环的正确对象。

解决方法

要让线程拿到创建时的j值,核心是让每个线程捕获当前迭代的值的副本而非变量引用,常见两种方式:

  1. 在循环内部创建局部变量保存当前j的值,让lambda捕获这个局部变量:
for (int j = 0; j < 6; j++)
{
    _waitNextBatch++;
    Console.WriteLine($"{_waitNextBatch}");

    BatchSensor bs = new BatchSensor { SensorName = $"batch - {j}" };
    // 保存当前迭代的j值到局部变量
    int currentJ = j;
    new Thread(() => SimulateBS(bs, currentJ)).Start();
}
  1. 如果使用C# 5及以上版本,也可以改用Parallel.For等并行循环方式,但第一种方法兼容性更好,适用于所有C#版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 19:47:32