C#很简单,为什么它没有产生正确的结果
本文关键字:结果 简单 为什么 | 更新日期: 2023-09-27 18:21:04
有人能告诉我为什么下面的结果不正确吗?它给了我1233,而我预期的是0123。
public static readonly object locker = new object();
public static List<int> queue = new List<int>();
public static void calculate(int input)
{
Thread.Sleep(1000);
lock (locker)
{
queue.Add(input);
}
}
[TestMethod]
public void TestT()
{
int[] _intList = new int[] { 0, 1, 2, 3 };
List<Thread> _threadList = new List<Thread>();
foreach (int num in _intList)
{
Thread t = new Thread(() => calculate(num));
t.Start();
_threadList.Add(t);
}
foreach (Thread t in _threadList) { t.Join(); }
foreach (var t in queue)
{
Console.WriteLine(t);
}
}
当我将其更改为使用_intList变量的副本时,我得到了0123的正确结果。有人能告诉我为什么会发生这种事吗?它被缓存在什么地方了吗?
foreach (int num in _intList)
{
int testNum = num;
Thread t = new Thread(() => calculate(testNum));
t.Start();
_threadList.Add(t);
}
当您将变量传递给lambda表达式时,它会被表达式捕获。所以这不是一个副本,而是你得到的变量。这是foreach和延迟执行(是否为多线程)的常见问题,因为foreach continue num正在获取它的下一个值,如果它这样做是因为线程要计算,那么将计算该值。
如果你没有对其进行多线程处理,而是在foreach之后调用lambda的结果,你会看到的结果是3 3 3 3,在这种情况下,你只是看到它们一个接一个的集合,因为启动线程所需的时间很可能与1次迭代相同。
当您复制变量时,该变量在foreach的范围内声明,并且每次都是一个新变量,它不会被更改为下一个成员,而该变量是被捕获的变量,从而为您提供正确的结果。这是正确的方法。你得到的结果并不意外,但也不能保证,你可以用第一个方法得到从0 1 2 3到3 3 3的任何结果,第二个方法可以保证正确的输出。