[英]Are static variables thread-safe? C#
我想创建一个存储DataTables的类,这将阻止我的应用程序每次要检索它时导入详细信息列表。 因此,这应该做一次,我相信下面的代码这样做,但我不确定它是否是线程安全的。
下面的代码位于我的三层应用程序的Business Layer部分,它将DataTable返回到表示层。
public class BusinessLayerHandler
{
public static DataTable unitTable;
public static DataTable currencyTable;
public static DataTable GetUnitList()
{
//import lists each time the application is run
unitTable = null;
if (unitTable == null)
{
return unitTable = DatabaseHandler.GetUnitList();
}
else
{
return unitTable;
}
}
public static DataTable GetCurrencyList()
{
//import lists each time the application is run
currencyTable = null;
if (currencyTable == null)
{
return currencyTable = DatabaseHandler.GetCurrencyList();
}
else
{
return currencyTable;
}
}
任何帮助表示赞赏,如果有更好的方法来缓存DataTable,请告诉我。
更新:
感谢您的意见,如果我理解正确,这是建议的方法:
public class BusinessLayerHandler
{
private static DataTable unitTable;
private static DataTable currencyTable;
private static readonly object unitTableLock = new object();
private static readonly object currencyTableLock = new object();
public static DataTable GetUnitList()
{
//import lists each time the application is run
//unitTable = null;
lock (unitTableLock)
{
if (unitTable == null)
{
return unitTable = DatabaseHandler.GetUnitList();
}
}
return unitTable;
}
public static DataTable GetCurrencyList()
{
//import lists each time the application is run
lock (currencyTableLock)
{
if (currencyTable == null)
{
return currencyTable = DatabaseHandler.GetCurrencyList();
}
}
return currencyTable;
}
}
看起来好像你想要做的只是加载一次并保持对它的引用。 您需要保护的只是初始化变量(如果它为空)。 空检查,锁定和空检查再次被称为双重检查锁定 ,并将很好地为您服务。 最佳做法是提供单独的锁定对象,以便您可以很好地控制锁的粒度。
请注意,这并不能阻止人们改变DataTable
的值,它只会阻止人们同时尝试初始化静态成员。
private static readonly object UnitTableLock = new object();
private static DataTable unitTable;
private static bool _ready = false;
public static DataTable GetUnitList()
{
if (!_ready)
{
lock (UnitTableLock)
{
if (!_ready)
{
unitTable = new DataTable; //... etc
System.Threading.Thread.MemoryBarrier();
_ready = true;
}
}
}
return unitTable;
}
只读取GetUnitList
的结果永远不会写入它。
我认为值得补充的是,Double Check Locking已经在.net framework 4.0中实现了一个名为Lazy
的类。 因此,如果您希望您的类默认包含锁定,那么您可以像这样使用它:
public class MySingleton
{
private static readonly Lazy<MySingleton> _mySingleton = new Lazy<MySingleton>(() => new MySingleton());
private MySingleton() { }
public static MySingleton Instance
{
get
{
return _mySingleton.Value;
}
}
}
它们不是线程安全的。 你应该考虑让自己的逻辑线程安全,例如,使用lock运算符。
如果您使用.net 4,则可以在数据表上使用ThreadLocal包装器
静态变量本身不是线程安全的。 您应该考虑到线程安全性。
有一个很好的链接可以帮助您入门: http : //en.csharp-online.net/Singleton_design_pattern%3A_Thread-safe_Singleton
除此之外,我强烈建议您使用比传统DataTable更现代的方法。 查看实体框架或NHibernate。 在数据层中实现它们将允许您从其余软件隐藏数据库详细信息,并让它在更高级别的抽象(POCO对象)上工作。
我觉得你应该没问题。 2个线程很可能确定数据表为空并且都读取了表,但只有一个unitTable
最后分配了unitTable
/ currencyTable
引用,所以最坏的情况是你不止一次将它们unitTable
。 但是一旦他们确定了,我认为你会很好。 因为你没有写信给他们。 Theat可能让一个处于不一致的状态。
如果要避免使用double init,可以将整个getter代码包装在lock
语句中。 这很像初始化单身人士。
还添加一个方法,让您再次将引用设置为null,以便强制刷新。
GJ
如果DataTables是只读的,那么你应该在填充它们时锁定它们,如果它们永远不会改变那么它们将是线程安全的。
public class BusinessLayerHandler
{
public static DataTable unitTable;
public static DataTable currencyTable;
private static readonly object unitTableLock = new object();
private static readonly object currencyTableLock = new object();
public static DataTable GetUnitList()
{
//import lists each time the application is run
lock(unitTableLock)
{
if (unitTable == null)
{
unitTable = DatabaseHandler.GetUnitList();
}
}
return unitTable;
}
public static DataTable GetCurrencyList()
{
//import lists each time the application is run
lock(currencyTableLock)
{
if (currencyTable == null)
{
currencyTable = DatabaseHandler.GetCurrencyList();
}
}
return currencyTable;
}
}
如果在此查找中需要非常高的性能,则可以使用ReaderWriterLockSlim类而不是每次完全锁定来限制应用程序中将发生的等待次数。
查看http://kenegozi.com/blog/2010/08/15/readerwriterlockslim-vs-lock,获取有关lock和ReaderWriterLockSlim之间差异的简短文章
编辑:(回答下面的评论)
unitTableLock对象用作Monitor类的句柄以进行同步。
有关.NET框架中的主题和同步的完整概述,我将向您指出这个非常广泛的教程http://www.albahari.com/threading/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.