我想要一个类似于多值字典的全局对象,在不同线程之间共享。
我希望对象只创建一次(例如从数据库中获取数据),然后由不同的线程使用。
该对象应该可以通过其他属性轻松扩展(目前只有 JobName 和 URL)。
如果可能的话,我宁愿避免锁定。
我面临以下问题:
- 下面显示的当前版本不是线程安全的;
- 我不能使用 ConcurrentDictionary 因为我扩展了 Dictionary 对象以允许每个键有多个值;
这是应该容易修改的对象结构:
public struct JobData
{
public string JobName;
public string URL;
}
我扩展了 Dictionary 对象以允许每个键有多个值:
public class JobsDictionary : Dictionary<string, JobData>
{
public void Add(string key, string jobName, string url)
{
JobData data;
data.JobName = jobName;
data.URL = url;
this.Add(key, data);
}
}
在线程之间共享的静态类。如您所见,它在第一次为特定作业调用时为特定作业创建了一个字典条目。
例如,第一次调用“earnings”时,它将创建“earnings”字典条目。这会产生线程安全问题:
public static class GlobalVar
{
private static JobsDictionary jobsDictionary = new JobsDictionary();
public static JobData Job(string jobCat)
{
if (jobsDictionary.ContainsKey(jobCat))
return jobsDictionary[jobCat];
else
{
String jobName;
String url = null;
//TODO: get the Data from the Database
switch (jobCat)
{
case "earnings":
jobName="EarningsWhispers";
url = "http://www.earningswhispers.com/stocks.asp?symbol={0}";
break;
case "stock":
jobName="YahooStock";
url = "http://finance.yahoo.com/q?s={0}";
break;
case "functions":
jobName = "Functions";
url = null;
break;
default:
jobName = null;
url = null;
break;
}
jobsDictionary.Add(jobCat, jobName, url);
return jobsDictionary[jobCat];
}
}
在每个线程中,我以这种方式获取特定的 Job 属性:
//Get the Name
string JobName= GlobalVar.Job(jobName).JobName;
//Get the URL
string URL = string.Format((GlobalVar.Job(jobName).URL), sym);
如何创建一个“实例化”一次的自定义字典(我知道它不是正确的术语,因为它是静态的......)并且它是线程安全的?
谢谢
更新
好的,这是新版本。
我通过删除 switch 语句并一次加载所有字典项来简化代码(无论如何我都需要它们)。
这种方案的好处是只加锁一次:当字典数据被添加时(第一个进入锁的线程将数据添加到字典中)。当线程访问字典进行阅读时,它没有被锁定。
它应该是线程安全的,并且不应该导致死锁,因为 jobsDictionary 是私有的。
public static class GlobalVar
{
private static JobsDictionary jobsDictionary = new JobsDictionary();
public static JobData Job(string jobCat)
{
JobData result;
if (jobsDictionary.TryGetValue(jobCat, out result))
return result;
//if the jobsDictionary is not initialized yet...
lock (jobsDictionary)
{
if (jobsDictionary.Count == 0)
{
//TODO: get the Data from the Database
jobsDictionary.Add("earnings", "EarningsWhispers", "http://www.earningswhispers.com/stocks.asp?symbol={0}");
jobsDictionary.Add("stock", "YahooStock", "http://finance.yahoo.com/q?s={0}");
jobsDictionary.Add("functions", "Functions", null);
}
return jobsDictionary[jobCat];
}
}
}