实施Singleton ...带锁吗?

时间:2013-03-28 13:00:42

标签: c#

在多线程应用程序(ASP.NET MVC)上,我需要一个全局设置类,其中包含从Web.Config中获取的常量和值。

我想让这个类静态,作为单身......并锁定?

public static class Settings {

  public static LoggerSettings Logger;
  public static MailerSettings Mailer;

  public class LoggerSettings {
    public String Levels { get { return ConfigurationManager.AppSettings["Logger.Levels"]; } }
    public const String Report = "team@xyz.com";
  } // LoggerSettings

  public class MailerSettings {
    public String Contact { get { return ConfigurationManager.AppSettings["Mailer.Contact"]; } }
  } // MailerSettings

}

我想我应该实行双锁?否?

我不确定这样做的最佳方法。请问,我可以帮忙吗?

谢谢你, 米格尔

5 个答案:

答案 0 :(得分:10)

  

我希望这个类是静态的,如单身

要在C#中正确实现单例,请参阅Jon Skeet关于哪些有效和无效的优秀摘要:

http://csharpindepth.com/Articles/General/Singleton.aspx

  

我想我应该实行双锁?否?

没有。双重检查锁定是一种低锁技术,因此在弱内存模型硬件上非常危险。当你偏离“幸福”模式时,你已经放弃了程序预期的所有希望。

我使用双重检查锁定的唯一情况是所有以下情况属实时:

  • 是否有广泛的经验证据单一检查锁定会导致性能不佳?
  • 让我们假设单次检查的表现是不可接受的。单一检查锁定通常会因争用而产生不良性能,因此第一步是消除争用。你能消除争用并获得可接受的表现吗?我只会使用双重检查锁定,如果无法删除争用性能问题是由获取无竞争锁定所需的几纳秒引起的。在后一种情况下:哇,这是一个快速的程序,那些纳秒是最慢的东西,哇,你有非常严重的性能要求,如果你计算个别纳秒
  • 让我们假设单次检查的性能是不可接受的,无法修复。 是否有另一种低锁技术,例如使用具有可接受性能的Interlocked.CompareExchange Lazy<T>?至少你知道CompareExchange和Lazy<T>是由专家编写的,并在所有硬件上适当地强制执行内存屏障。如果已经实施了更好的工具,请不要使用双重检查锁定。
  • 让我们假设这些工具都没有提供可接受的性能。 双重检查锁定是否可以提供可接受的性能?如果没有,则不使用

答案 1 :(得分:5)

如我所见,你只读数据。所以你不需要锁定IMO。 使用静态构造函数来初始化变量,例如Report(使它也是静态的)。

答案 2 :(得分:1)

如果您喜欢静态和单身,请尝试这种方式:

public static class Settings {
  private static readonly object LockObject = new object();
  private static LoggerSetting LoggerInstance;

  public static LoggerSetting LoggerSettings {
    get {
      lock (LockObject) {
         if (LoggerInstance == null)
           LoggerInstance = new LoggerInstance(); 

         return LoggerInstance;
       }
     }
   }

   public class LoggerSetting {
     public String Levels {
       get { return ConfigurationManager.AppSettings["Logger.Levels"]; }
     } 

     public const String Report = "team@xyz.com";
   }
}

并使用它:

string x = Settings.LoggerSEttings.Report;

答案 3 :(得分:1)

看看Jon Skeet的文章Implementing the Singleton Pattern in C#

最简单,最好的选择:

public sealed class Settings
{
    private static readonly Settings instance = new Settings();

    public LoggerSettings Logger { get; private set; }
    public MailerSettings Mailer { get; private set; }

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Settings()
    {
    }

    private Settings()
    {
       Logger = new LoggerSettings();
       Mailer = new MailerSettings();
    }

    public static Settings Instance { get { return instance;} }
}

public class LoggerSettings {

    public LoggerSettings()
    {
        Levels = ConfigurationManager.AppSettings["Logger.Levels"];
    }

    public String Levels { get; private set; }
    public const String Report = "team@xyz.com";

}

// Mailer settings would look similar

由于您只是从此实例中读取数据,因此不需要任何锁定。单例实例是在任何其他线程可以访问之前创建的,因此也不需要锁定它。

用法:

 Settings.Instance.Mailer.Contact

答案 4 :(得分:-1)

如果您仍然希望继续使用单例实例

    public class MySettings{
    private static Object lockObj = new Object();
    private MySettings() {} // private .ctor

    private static MySettings _instance;

    public static MySettings MySingleSettings{
     get{
      if(_instance == null){
      lock(lockObj){
        if(_instance == null)
          _instance = new MySettings();
        }
      }
       return _instance;
    }
}