输出的时候发现currentId不是预期的10000。为什么?如何纠正
c#
这段代码是我偶然看到的。代码大致如下。
public class Question2
{
public void Run()
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10000; i++)
{
tasks.Add(Task.Factory.StartNew(() =>
{
GetNextId();
}));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("currentId=" + GetCurrentId());
Console.ReadKey();
}
private int currentId;
public int GetNextId()
{
currentId++;
return currentId;
}
public int GetCurrentId()
{
return currentId;
}
}
我不知道为什么结果不是 10000?有人可以告诉我为什么以及如何纠正它。
回答
你刚刚发现了线程安全的话题!currentId++翻译成
- 从内存中读取 currentId 的值
- 将此值加一
- 将此新值写回内存
现在想象你的循环只进行到 i < 3。第一个线程在第 1 步并读取值 0。在进入第 2 步之前,第二个线程在第 1 步并且也读取 0。现在两个线程都进入第 2 步3、将两个1都写入内存。现在第三个线程启动,将从内存中读取 1,将其增加到 2 并将其写入内存。现在您有 2 而不是预期值 3。
要解决此问题,您可以使用Interlocked.Increment:
private int currentId;
public int GetNextId()
{
return Interlocked.Increment(ref currentId);
}
但请注意,根据您的用例,当您使用GetNextId().