I am wondering which following code is best:
private static volatile OrderedDictionary _instance;
private static readonly Object SyncLock = new Object();
private static OrderedDictionary Instance
{
get { return _instance ?? (_instance = new OrderedDictionary()); }
}
public static Mea Add(Double pre, Double rec)
{
lock (SyncLock)
{
...
}
}
Or is it OK and better IMO just use the following?
private static volatile OrderedDictionary _instance;
private static OrderedDictionary Instance
{
get { return _instance ?? (_instance = new OrderedDictionary()); }
}
public static Mea Add(Double pre, Double rec)
{
lock (Instance)
{
...
}
}
Based on Mike Strobel's answer I have done to following changes:
public static class Meas
{
private static readonly OrderedDictionary Instance = new OrderedDictionary();
private static readonly Object SyncLock = new Object();
public static Mea Add(Double pre, Double rec)
{
lock (SyncLock)
{
Instance.Add(pre, rec);
...
}
}
}
Mike Strobel's advice is good advice. To sum up:
Lazy<T>
type; it was designed by experts who know what they are doing. The two pieces of code are not equivalent. The former ensures that all threads will always use the same lock object. The latter locks a lazily-initialized object, and there is absolutely nothing preventing multiple instantiations of your _instance
dictionary, resulting in contents being lost.
What is the purpose of the lock? Does the serve a purpose other than to guarantee single-initialization of the dictionary? Ignoring that it fails to accomplish this in the second example, if that is its sole intended purpose, then you may consider simply using the Lazy<T>
class or a double-check locking pattern.
But since this is a static member (and does not appear to capture outer generic parameters), it will presumably only be instantiated once per AppDomain. In that case, just mark it as readonly
and initialize it in the declaration. You're probably not saving much this way.
Since you are concerned with best practices: you should never use the lock
construct on a mutable value; this goes for both static and instance fields, as well as locals. It is especially bad practice to lock on a volatile field, as the presence of that keyword indicates that you expect the underlying value to change. If you're going to lock on a field, it should almost always be a readonly
field. It's also considered bad practice to lock on a method result; that applies to properties too, as properties are effectively a pair of specially-named accessor methods.
If you do not expose the Instance
to other classes, the second approach is okay (but not equivalent). It's best practice to keep the lock object private to the class that is using it as a lock object. Only if other classes can also take this object as lock object you may run into issues.
(For completeness and regarding @Scott Chamberlain comment:) This assumes that the class of Instance
is not using lock (this)
which contrary represents bad practice.
Nevertheless, the property could make problems. The null coalescing operator is compiled to a null check + assignment... Therefore you could run into race conditions. You might want to read more about this. But also consider to remove the lazy initialization at all, if possible.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.