C# 在后台线程上初始化单例的公共模式
我目前有一个单例,它最多需要10秒来初始化。然而,我不希望我的用户因为这个初始化而受到惩罚(等待),所以我宁愿在应用程序启动期间在后台线程上引导这个组件。以下是我所拥有的: 单身人士:C# 在后台线程上初始化单例的公共模式,c#,.net,multithreading,design-patterns,singleton,C#,.net,Multithreading,Design Patterns,Singleton,我目前有一个单例,它最多需要10秒来初始化。然而,我不希望我的用户因为这个初始化而受到惩罚(等待),所以我宁愿在应用程序启动期间在后台线程上引导这个组件。以下是我所拥有的: 单身人士: public class MySingleton { private static MySingleton _instance; private static readonly object _locker = new object(); private MySingleton()
public class MySingleton
{
private static MySingleton _instance;
private static readonly object _locker = new object();
private MySingleton()
{
Init();
}
public static MySingleton Instance
{
if(_instance == null) _instance = new MySingleton();
return _instance;
}
public void Init()
{
lock(_locker)
{
if(_instance != null) return;
// long running code here...
}
}
}
应用程序启动:
Task.Factory.StartNew(() => MySingleton.Instance.Init());
这段代码确实有效,可以防止双重初始化,防止用户在初始化之前需要它,还可以防止有人忘记调用init()
但是,它感觉有点笨重,原因有两个:
a) 我将在启动时进入Init方法两次。
b) 我希望在单例中执行线程,但必须启动初始化
有没有更干净/更好/更好的方法来处理这个问题
提前感谢大家的帮助
**编辑:正如评论中指出的,Init被错误地定义为私有。它应该是公开的,并且已经被纠正了 您应该定义并调用singleton类,如下所示
var instance = MySingleton.Instance;
while (true)
{
/// check for whether singleton initialization complete or not
if (MySingleton.Initialized)
{
break;
}
}
public class MySingleton
{
private static MySingleton _instance;
private static readonly object _locker = new object();
public static bool Initialized { get; set; }
private MySingleton()
{
ThreadPool.QueueUserWorkItem(call => Init());
}
public static MySingleton Instance
{
get
{
if (_instance == null)
_instance = new MySingleton();
return _instance;
}
}
private void Init()
{
lock (_locker)
{
if (Initialized)
return;
// long running code here...
for (int i = 0; i < 10000; i++)
{
}
Initialized = true;
}
}
}
var instance=MySingleton.instance;
while(true)
{
///检查单例初始化是否完成
if(MySingleton.Initialized)
{
打破
}
}
公共课米辛格尔顿
{
私有静态MySingleton_实例;
私有静态只读对象_locker=new object();
公共静态bool已初始化{get;set;}
二等兵迈辛格尔顿()
{
QueueUserWorkItem(call=>Init());
}
公共静态MySingleton实例
{
得到
{
if(_instance==null)
_instance=new MySingleton();
返回_实例;
}
}
私有void Init()
{
锁(储物柜)
{
如果(已初始化)
返回;
//长时间运行的代码在这里。。。
对于(int i=0;i<10000;i++)
{
}
初始化=真;
}
}
}
使用静态构造函数触发它,并使用ManualResetEvent
进行同步。它为您提供了一个解决方案,其中所有工作都是在实际类中完成的。因此,它不依赖于应该有人调用您的init方法
public class MySingleton
{
private static MySingleton _instance;
private static ManualResetEvent _initEvent = new ManualResetEvent(false);
static MySingleton()
{
ThreadPool.QueueUserWorkItem(state => Init());
}
public static MySingleton Instance
{
_initEvent.Wait();
return _instance;
}
private static void Init()
{
_instance = new MySingleton();
// long running code here...
_initEvent.Set();
}
}
一旦触发,事件将保持有信号状态,这意味着实例属性将在Init方法完成后尽快返回。我将执行
任务。
:
类程序
{
静态void Main(字符串[]参数)
{
MySingleton.Init();
睡眠(7000);
WriteLine(“获取实例…”);
var mySingleton=mySingleton.Instance;
WriteLine(“获得实例”);
}
公共课米辛格尔顿
{
私有静态惰性实例;
公共静态MySingleton实例
{
获取{return instance.Value;}
}
公共静态void Init()
{
var initTask=Task.Factory.StartNew(()=>
{
对于(int i=0;i<10;i++)
{
睡眠(1000);
WriteLine(“Doint init stuff{0}…”,i);
}
返回新的MySingleton();
});
instance=newlazy(()=>initTask.Result);
}
私有MySingleton(){}
}
}
您应该使用Lazy
来初始化您的单例,以便在实际使用单例之前卸载初始化。Jon在那篇文章中指出“我个人偏好解决方案4:”这不是懒惰的解决方案。请阅读这篇文章,了解他的推理和更多信息。@MitchWheat-Heh,我想(在我读了10多次之后)我从来没有读过这篇文章。这将教会我保持沉默(可能不是这样)当Init()是一个私有方法时,你如何在启动时调用它?@M.Babcock:最后一部分只是(相对而言)最近添加的。非常好的解决方案!谢谢但有两个问题:a)是否有理由将UserWorkItem而不是Task.Factory.StartNew()排入队列?b) 是否需要使用手动重置事件而不是自动重置事件?a)否,个人偏好。b) 对AutoResetEvent
将在第一个Wait
已完成时重置信号并阻止所有调用者轻微问题:仅在第一次使用类成员时调用静态构造函数。因此,在应用程序启动期间不会运行Init()。@pdalb01是正确的。提出的解决方案(最迟)将在首次使用时运行。您可以添加一个伪函数来触发命令的实例化。类似于publicstaticboolcreateInstanceInBackground(){return}\u instance==null;}的东西,如果您想强制启动,可以在主构造函数中调用它。
class Program
{
static void Main(string[] args)
{
MySingleton.Init();
Thread.Sleep(7000);
Console.WriteLine("Getting instance...");
var mySingleton = MySingleton.Instance;
Console.WriteLine("Got instance.");
}
public class MySingleton
{
private static Lazy<MySingleton> instance;
public static MySingleton Instance
{
get { return instance.Value; }
}
public static void Init()
{
var initTask = Task.Factory.StartNew(() =>
{
for(int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
Console.WriteLine("Doint init stuff {0}...", i);
}
return new MySingleton();
});
instance = new Lazy<MySingleton>(() => initTask.Result);
}
private MySingleton() { }
}
}