一般常见写法,但是不是线程安全的,在多个线程访问 if (instance == null) 时会,同时进入if语句内创建多个Singleton实例。
public class Singleton
{
// 直接初始化单例实例
private static Singleton instance ;
public static Singleton Instance
{
get
{
if (instance != null)
{
return instance;
}
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
// 私有构造函数
private Singleton()
{
// 这里可以进行一些初始化工作
Console.WriteLine("Singleton instance created.");
}
public void SomeMethod()
{
Console.WriteLine("SomeMethod called.");
}
}
我们测试一下:
class Program
{
static void Main()
{
// 创建50个线程访问单例实例
for (int i = 0; i < 50; i++)
{
System.Threading.ThreadPool.QueueUserWorkItem((state) =>
{
Task.Delay(50).Wait();
Singleton.Instance.SomeMethod();
});
}
Console.ReadLine();
}
}
结果:
可以发现有多个实例被创建
简单的线程安全做法
public class Singleton
{
// 直接初始化单例实例
private static readonly Singleton instance = new Singleton();
public static Singleton Instance => instance;
// 私有构造函数
private Singleton()
{
// 这里可以进行一些初始化工作
Console.WriteLine("Singleton instance created.");
}
public static int a = 0;
}
但是这样在我们访问如何静态字段时都会创建单例实例
测试如下:
使用 Monitor 来确保线程安全
public class Singleton
{
private static Singleton instance;
private static readonly object syncRoot = new object();
// 公共属性,用于获取单例实例
public static Singleton Instance
{
get
{
if (instance != null)
{
return instance;
}
Monitor.Enter(syncRoot);
if (instance == null)
{
instance = new Singleton();
}
Monitor.Exit(syncRoot);
return instance;
}
}
// 私有构造函数,确保外部不能直接实例化
private Singleton()
{
Console.WriteLine("Singleton instance created.");
// 这里可以进行一些初始化工作
}
// 其他成员方法/属性
public void SomeMethod()
{
Console.WriteLine("SomeMethod called.");
}
}
使用 Lazy <T> 来延迟加载,Lazy <T>内部调用的创建也是线程安全的
public class Singleton
{
// 私有静态实例变量
private static readonly Lazy<Singleton> instance = new Lazy<Singleton>(() => new Singleton());
// 公共属性,用于获取单例实例
public static Singleton Instance
{
get
{
return instance.Value;
}
}
// 私有构造函数,确保外部不能直接实例化
private Singleton()
{
Console.WriteLine("Singleton instance created.");
// 这里可以进行一些初始化工作
}
// 其他成员方法/属性
public void SomeMethod()
{
Console.WriteLine("SomeMethod called.");
}
}
这部分读者可以自行测试