我目前有一个单例,初始化最多可能需要10秒。但是,我不希望我的用户对此初始化进行惩罚(等待),因此我宁愿在应用程序启动期间在后台线程上引导此组件。这就是我所拥有的:
的Singleton:
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被误认为是私有的。它应该是公开的并且已得到纠正。
答案 0 :(得分:9)
使用静态构造函数触发它,并使用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方法完成时,Instance属性将尽快返回。
答案 1 :(得分:0)
您应该定义并调用单例类,如下所示......
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;
}
}
}
答案 2 :(得分:0)
&#39; d可以使用Task<T>
:
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() { }
}
}