我有一些静态的Dictionary对象,它为我保存了一些常量列表,所以每次我的网站加载时我都不必从数据库加载它们(例如:国家列表,类别列表)。
所以我有一个静态函数来检查实例是否为null,如果是查询数据库,则实例化静态变量,并用数据填充它。
由于它是一个网站,可能会有一个案例,当对象为空时,不止一个人试图同时访问该信息,所有做的人将同时调用该进程(这是实际上没有必要,导致对数据库的不必要的查询,并可能导致列表中的重复对象。
我知道有一种方法可以使这种加载线程安全(只是不确定如何) - 有人能指出我正确的方向吗?我应该使用锁?
由于
更新II:
这就是我写的(这是一个很好的线程安全代码吗?)
private static Lazy<List<ICountry>> _countries = new Lazy<List<ICountry>>(loadCountries);
private static List<ICountry> loadCountries()
{
List<ICountry> result = new List<ICountry>();
DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
foreach (DataRow dr in dtCountries.Rows)
{
result.Add(new Country
{
ID = Convert.ToInt32(dr["CountryId"]),
Name = dr["Name"].ToString()
});
}
return result;
}
public static List<ICountry> GetAllCountries()
{
return _countries.Value;
}
答案 0 :(得分:0)
如果您使用的是.NET 4.0,则可以使用内置的Lazy泛型类。
private static Lazy<YourObject> data = new Lazy<YourObject>(YourInitializationFunction);
public static YourObject Data { get { return data.Value; } }
请注意,您必须将静态构造函数添加到您定义它的类中,否则它不是完全线程安全的。
如果您不使用.NET 4.0+,则可以编写自己的代码。基本模式看起来像这样:
private static YourObject data;
private static object syncObject = new object();
public static YourObject Data
{
get
{
if (data == null)
{
lock (syncObject)
{
if (data != null)
return data;
var obj = new YourObject();
return (YourObject)Interlocked.Exchange(ref data, obj);
}
}
return data;
}
}
答案 1 :(得分:0)
您可以使用Lazy以惰性和线程安全的方式加载资源:
Lazy<List<string>> countries =
new Lazy<List<string>>(()=> /* get your countries from db */);
更新
public static class HelperTables
{
private static Lazy<List<ICountry>> _countries;
static HelperTables //Static constructor
{
//Instantiating the lazy object in the static constructor will prevent race conditions
_countries = new Lazy<List<ICountry>>(() =>
{
List<ICountry> result = new List<ICountry>();
DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
foreach (DataRow dr in dtCountries.Rows)
{
result.Add(new Country
{
ID = Convert.ToInt32(dr["CountryId"]),
Name = dr["Name"].ToString()
});
}
return result;
});
}
public static List<ICountry> GetAllCountries()
{
return _countries.Value;
}
}