我已经在网络上搜索,我得到一个有点困惑的多线程(lock
,Monitor.Enter
,volatile
等),而不是要求的解决方案在这里,我已经试过一些“自制”关于多线程的管理,我想有你的意见。
这是我的上下文:
- 我有一个包含静态的静态类 Dictionary<int,string>
-我有很多的任务(假设1000)阅读本Dictionary
每秒钟
-我有一个另一项任务,即会更新这个Dictionary
每10s。
这是缓存的代码:
public static class Cache
{
public static bool locked = false;
public static Dictionary<int, string> Entries = new Dictionary<int, string>();
public static Dictionary<int, string> TempEntries = new Dictionary<int, string>();
// Called by 1000+ Tasks
public static string GetStringByTaskId(int taskId)
{
string result;
if (locked)
TempEntries.TryGetValue(taskId, out result);
else
Entries.TryGetValue(taskId, out result);
return result;
}
// Called by 1 task
public static void UpdateEntries(List<int> taskIds)
{
TempEntries = new Dictionary<int, string>(Entries);
locked = true;
Entries.Clear();
try
{
// Simulates database access
Thread.Sleep(3000);
foreach (int taskId in taskIds)
{
Entries.Add(taskId, $"task {taskId} : {DateTime.Now}");
}
}
catch (Exception ex)
{
Log(ex);
}
finally
{
locked = false;
}
}
}
这是我的问题:
程序运行,但我不明白为什么方法中的两次“锁定”bool
赋值UpdateEntries
不会产生多线程异常,因为它被另一个线程“每次”读取
有没有更传统的方法来处理这个问题,我觉得这是一种奇怪的方法?
处理此问题的传统方法是使用ConcurrentDictionary。此类是线程安全的,设计用于多个线程对其进行读写。您仍然需要注意潜在的逻辑问题(例如,如果必须同时添加两个键才能让其他线程看到它们中的任何一个),但是对于大多数操作而言,无需额外锁定就可以了。
针对您的特定情况处理此问题的另一种方法是使用普通字典,但一旦它可供读者线程使用,就将其视为不可变的。这将更有效,因为它避免了锁定。
public static void UpdateEntries(List<int> taskIds)
{
//Other threads can't see this dictionary
var transientDictionary = new Dictionary<int, string>();
foreach (int taskId in taskIds)
{
transientDictionary.Add(taskId, $"task {taskId} : {DateTime.Now}");
}
//Publish the new dictionary so other threads can see it
TempEntries = transientDictionary;
}
一旦字典被分配到TempEntries
(其他线程可以访问它的唯一地方),它就永远不会被修改,所以线程问题就消失了。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句