繁体   English   中英

线程安全加载静态集合

[英]thread-safe loading of a static collection

我有一些静态的Dictionary对象为我保存一些常量列表,因此我不必在每次我的网站加载时都从数据库中加载它们(例如:国家列表,类别列表)。

因此,我有一个静态函数,该函数检查实例是否为null,是否正在查询数据库,实例化静态变量,并用数据填充它。

由于这是一个网站,因此有可能会有一个以上的人试图同时访问该信息,而对象为null,那么所有这样做的人都会同时调用该过程(这实际上不是必需的) ,会导致对数据库的不必要查询,并可能导致列表中的对象重复。

我知道有一种方法可以使这种加载线程安全(只是不太确定如何)-有人可以指出我正确的方向吗? 我应该使用锁吗?

谢谢

更新二:

这就是我写的(这是一个很好的线程安全代码吗?)

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;
}

如果使用的是.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;
    }
}

您可以使用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;
   }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM