实现Singleton ..与锁

本文关键字:与锁 Singleton 实现 | 更新日期: 2023-09-27 18:06:31

在一个多线程应用程序(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
}

我认为我应该实现双锁?没有?

我不确定做这件事的最好方法。请帮我一下好吗?

谢谢你,米格尔

实现Singleton ..与锁

我希望这个类是静态的,作为单例

要在c#中正确地实现单例,请参阅Jon Skeet关于什么可以工作和不可以工作的优秀总结:

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

我认为我应该实现双锁?没有?

。双重检查锁定是一种低锁技术,因此在弱内存模型硬件上非常危险。一旦你稍微偏离了"受祝福的"模式,你就放弃了对程序行为可预测性的所有希望。

只有当下列所有都为真时,我才会使用双重检查锁定:
  • 是否有广泛的经验证据表明单检查锁定产生较差的性能?
  • 假设单检查性能是不可接受的。由于争用,单检查锁定通常会产生较差的性能,因此第一步是消除争用。您能消除争用并获得可接受的性能吗?只有当不可能移除争用,或者性能问题是由于获取一个未争用锁所花费的几纳秒造成的,我才会使用双重检查锁定。在后一种情况下:哇,这是一个快速的程序,这些纳秒是最慢的东西,哇,如果你计算单个纳秒,你有相当严重的性能要求。
  • 让我们假设单检查性能是不可接受的,并且无法修复。是否有另一种低锁技术,比如使用Interlocked。CompareExchangeLazy<T>具有可接受的性能?至少您知道CompareExchange和Lazy<T>是由专家编写的,并且在所有硬件上适当地强制了内存屏障。如果已经实现了更好的工具,不要使用双重检查锁定。
  • 让我们假设这些工具都没有提供可接受的性能。双重检查锁定是否提供可接受的性能?如果没有,就不要使用

在我看来,您只读取数据。所以你不需要锁在这里。使用静态构造函数来初始化变量,比如Report(将其设置为静态)。

看看Jon Skeet的文章《在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

如果您希望它是静态的并且是单例的,那么可以这样尝试:

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;

如果您还想继续使用单例实例

    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;
    }
}