c# - 输出的时候发现currentId不是预期的10000。为什么?如何纠正它
问题描述
我偶然看到的这段代码。代码大致如下。
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()
.
推荐阅读
- ios - App Store - 帮助回答“缺少合规性”(使用 Expo + Firebase)
- javascript - 带有单击按钮以关闭的工具提示 - 传单
- javascript - 上传到 GCP 存储或使用 bucket.getFiles() 后将文件名保存在数据库中
- ruby - 无法在 Windows 10 上安装/使用 LocomotiveCMS Wagon
- sql - 如何编写 SQL 以在一行中显示两列的不同值
- docusignapi - DocuSign Power 表单中的解密
- jquery - Javascript 通过单击元素添加通用选择器 CSS 规则 - 或更新通用选择器规则以具有类名
- c# - 从 C# 项目执行 .ps1 文件作为参数
- java - 如何在android中打开用于选择wifi的小弹出菜单?
- google-app-engine - 如何将 Terraform `google_app_engine_domain_mapping` 与服务帐户一起使用?