如何轻松地模拟这种单例模式的非线程安全性
本文关键字:线程 安全性 单例模式 何轻松 模拟 | 更新日期: 2023-09-27 18:19:19
根据Jon Skeet的文章,下面的模式是不好的,因为它不是线程安全的。
// Bad code! Do not use!
public sealed class Singleton
{
private static Singleton instance = null;
private Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
我还没有学过线程,所以它对我来说有点抽象。你能给我一个简单的代码来模拟线程问题(当问题发生时我们得到通知)?
这很简单,只是让一些东西并行访问你的单例中的属性,例如像这个控制台应用程序。
class Program
{
static void Main(string[] args)
{
var threads = Enumerable.Repeat(new Action(() => Console.WriteLine(Singleton.Instance.guid)), 10);
Parallel.ForEach(threads, t => t());
Console.Read();
}
}
(我已经添加了一个guid属性到你的类来测试)
public sealed class Singleton
{
public Guid guid = Guid.NewGuid();
private static Singleton instance = null;
private Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
这个单例实现的问题是两个线程可以同时访问getter,每个线程都将创建一个新实例。因此,第一个线程可能最终与第二个线程具有不同的实例…这会导致意想不到的行为。
这只是对OP评论的回复:
static void Main(string[] args)
{
int test = 5;
Task<Singleton>[] arr =
{
Task<Singleton>.Factory.StartNew(() => Singleton.Instance),
Task<Singleton>.Factory.StartNew(() => Singleton.Instance),
};
Task.WaitAll(arr);
foreach (var item in arr)
{
Singleton s = item.Result;
s.MyProperty = test++;
Console.WriteLine(s.MyProperty);
}
}
MyProperty只是我添加的一个int属性。