实现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
}
我认为我应该实现双锁?没有?
我不确定做这件事的最好方法。请帮我一下好吗?
谢谢你,米格尔
我希望这个类是静态的,作为单例
要在c#中正确地实现单例,请参阅Jon Skeet关于什么可以工作和不可以工作的优秀总结:
http://csharpindepth.com/Articles/General/Singleton.aspx我认为我应该实现双锁?没有?
。双重检查锁定是一种低锁技术,因此在弱内存模型硬件上非常危险。一旦你稍微偏离了"受祝福的"模式,你就放弃了对程序行为可预测性的所有希望。
只有当下列所有都为真时,我才会使用双重检查锁定:- 是否有广泛的经验证据表明单检查锁定产生较差的性能?
- 假设单检查性能是不可接受的。由于争用,单检查锁定通常会产生较差的性能,因此第一步是消除争用。您能消除争用并获得可接受的性能吗?只有当不可能移除争用,或者性能问题是由于获取一个未争用锁所花费的几纳秒造成的,我才会使用双重检查锁定。在后一种情况下:哇,这是一个快速的程序,这些纳秒是最慢的东西,哇,如果你计算单个纳秒,你有相当严重的性能要求。
- 让我们假设单检查性能是不可接受的,并且无法修复。是否有另一种低锁技术,比如使用Interlocked。CompareExchange或
Lazy<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;
}
}