public class Helper
{
private static List<TimeZoneMap> timeZoneList = null;
public static List<TimeZoneMap> GetTimeZoneList()
{
if (timeZoneList == null)
{
timeZoneList = new List<TimeZoneMap>();
timeZoneList.Add(new TimeZoneMap() { Id = "Dateline Standard Time", DisplayName = "(UTC-12:00) International Date Line West" });
timeZoneList.Add(new TimeZoneMap() { Id = "UTC-11", DisplayName = "(UTC-11:00) Coordinated Universal Time-11" });
timeZoneList.Add(new TimeZoneMap() { Id = "Aleutian Standard Time", DisplayName = "(UTC-10:00) Aleutian Islands" });
}
}
The timeZoneList gets initialized inside an instance class (Helper) but it is static a list.
A static method add items to this list based on null check.
In a multi threaded environment, the timeZoneList does not have all the values and return nulls randomly. This occurs for only 2 to 3 random instance out of the 200.
What we are doing wrong here ?
- Static List
- Static Method
- An Instance class initialization inside the static list ?
- or calling the same static method from different instances of parent class. ?
This is not frequently happening and cannot guess when the issue occurs as well.
Thinking of making this list as static readonly collection. But still doubt that would make the list read only. What on the initial load we get only 5 instead of all !?
If multiple threads call
GetTimeZoneList()at the same time whiletimeZoneListis null, you'll get a race condition. The fact that it is static is irrelevant here.The reason for this is that, if, say, two threads enter the method at the same time while the list is null, they'll both enter the
ifat the same time. That is bad, because now you have concurrent writes to thetimeZoneListfield, concurrent modification to a non thread-safe collection, or both. Ultimately, your problem is that you're sharing mutable states between threads, and that is always bad.There's also the other issue of using a mutable collection (
List<T>) for something that might be shared between threads, which creates the risk that some part of the code modifies it afterwards, wreaking further havoc. I recommend using something likeImmutableArray<T>instead:Once the
ImmutableArray<T>is constructed, it cannot be changed, preventing other problems. You can then choose to returnIReadOnlyCollection<T>orIReadOnlyList<T>to hide that implementation detail.Let's look at your options.
1. Make it immutable
Initialisation of a static field is guaranteed to happen only once, so this is inherently thread safe:
It does have the issue of making the initialisation eager, which might not be what you want. To keep it lazy, read on.
2. Lock it
Use the
lockstatement with an object to control access to the field:That's fairly straightforward, but a bit verbose. Also, it looks like a singleton, and I don't like singletons. You could also do another null check outside of the lock to avoid locking it unnecessarily, but that's an optimisation. Up to you.
Use
Lazy<T>For me, this is the best approach: it's simpler, leaner, and more robust.
Lazy<T>is a class that, as its name implies, contains a value that is lazily initialised. By default, this object performs its initialisation in a thread safe manner (specifically, with theExecutionAndPublicationthread safety mode), so, you could do this:The above eagerly creates the lazy object, specifying the method to use as its factory. The list is initially not created. The first time some gets the lazy's
Value(by callingGetTimeZoneList()), it will then be properly initialised. Subsequent calls return the same list. If multiple thread do so at the same time, the factory method will still be called only once, and all threads then get the same exact list.