I want to create a class which stores DataTables, this will prevent my application to import a list of details each time I want to retrieve it. Therefore this should be done once, I believe that the following code does so, but I am not sure if it is thread-safe.
The below code is in the Business Layer Section of my three tier application, it is returning a DataTable to the Presentation Layer.
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; } }
Any help is appreciated, if there is a better way how to cache a DataTable please let me know.
Update:
Thanks to your opinions, this is the suggested method to do it, if I understood correctly:
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; } }
Static variables are not thread safe. Instance variables do not require thread synchronization unless shared among threads. But, static variables are always shared by all the threads in the process. Hence, access to static variable is not thread safe.
Each thread will share the same static variable which is mostly likely a global variable.
Local variables are stored on the stack, each thread has a reference to its own set of variables on the stack, so local variables are thread safe. Yes.
It appears as though all you want to do is load it once and keep a reference to it. All you need to guard is initialising the variable if it's null. Null checking, locking and null checking again is called Double Check Locking and will work well for you. It's best practice to provide a separate locking object, so you have good control over granularity of locks.
Note this doesn't stop people from mutating the value inside the DataTable
it only stops people from trying to initialise the static member at the same time.
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; }
Only read from the result of GetUnitList
never write to it.
Amended with reference to http://en.wikipedia.org/wiki/Double-checked_locking
I thought it would be worth adding that Double Check Locking has since been implemented in .net framework 4.0 in a class named Lazy
. So if you would like your class to include the locking by default then you can use it like this:
public class MySingleton { private static readonly Lazy<MySingleton> _mySingleton = new Lazy<MySingleton>(() => new MySingleton()); private MySingleton() { } public static MySingleton Instance { get { return _mySingleton.Value; } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With