静态variables是线程安全的吗? C#
我想创build一个存储数据表的类,这将阻止我的应用程序每次我想要检索时导入一个详细列表。 因此,应该这样做一次,我相信下面的代码是这样做的,但我不确定它是否是线程安全的。
下面的代码位于我的三层应用程序的业务层部分,它将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; } }
任何帮助表示赞赏,如果有更好的方法如何cachingDataTable请让我知道。
更新:
感谢您的意见,这是build议的方法来做到这一点,如果我理解正确的话:
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; } }
看起来好像你想要做的就是加载一次,并保持一个引用。 所有你需要防范的是初始化variables,如果它是空的。 空检查,locking和空检查再次被称为双检查locking ,并将为您工作的很好。 提供一个单独的locking对象是最好的实践,所以您可以很好地控制锁的粒度。
注意,这不会阻止人们改变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
的结果中GetUnitList
不会写入。
我认为值得一提的是Double Check Locking已经在名为Lazy
.net framework 4.0中实现了。 所以,如果你希望你的类默认包含locking,那么你可以像这样使用它:
public class MySingleton { private static readonly Lazy<MySingleton> _mySingleton = new Lazy<MySingleton>(() => new MySingleton()); private MySingleton() { } public static MySingleton Instance { get { return _mySingleton.Value; } } }
他们不是线程安全的。 你应该考虑让自己的逻辑线程安全,例如,使用locking运算符。
如果你在.net 4上,你可以在你的数据表上使用ThreadLocal包装器
静态variables本身不是线程安全的。 你应该考虑线程安全的devise。
有一个很好的链接,让你开始: http : //en.csharp-online.net/Singleton_design_pattern%3A_Thread-safe_Singleton
除此之外,我强烈build议您使用比传统DataTable更现代的方法。 查看entity framework或NHibernate。 在你的数据层中实现它们将允许你从软件的其余部分隐藏数据库细节,并让它在更高层次的抽象(POCO对象)上工作。
我认为你应该没问题。 有两个线程可能会确定数据表为null,并且都读取表,但是最后只有一个线程可以分配unitTable
/ currencyTable
引用,所以最坏的情况是您unitTable
它们。 但一旦确定,我认为你会很好。 只要你不写信给他们。 Theat可以让一个处于不一致的状态。
如果你想避免双重初始化,你可以把整个getter代码包装在一个lock
语句中。 这很像初始化一个单身人士。
还要添加一个方法,让您将引用再次设置为空,以便您可以强制刷新。
GJ
如果DataTables是只读的,那么当你填充它们时你应该locking它们,如果它们永不改变,那么它们将是线程安全的。
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类,而不是每次完全locking,以限制应用程序中发生的等待次数。
查看http://kenegozi.com/blog/2010/08/15/readerwriterlockslim-vslock关于锁与ReaderWriterLockSlim之间的区别的简短文章;
编辑:(下面的评论回答)
unitTableLock对象被用作Monitor类中的句柄来同步。
有关.NET框架中的Theading和同步的完整概述,我将向您指出这个非常广泛的教程http://www.albahari.com/threading/