简体   繁体   中英

Locking a private static object

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:

  • Lock only objects that are specifically intended to be locks .
  • Those lock objects should be private readonly fields that are initialized in their declarations.
  • Do not try to roll your own threadsafe lazy initialization. Use the Lazy<T> type; it was designed by experts who know what they are doing.
  • Lock all accesses to the protected variable.
  • Violate these sensible guidelines when both of the following two conditions are true: (1) you have a empirically demonstrated customer-impacting performance problem and solid proof that going with a more complex low-lock thread safety system is the only reasonable solution to the problem, and (2) you are a leading expert on the implications of processor optimizations on low-lock code. For example, if you are Grant Morrison or Joe Duffy.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM