单例模式,属于创建类型的一种常用的设计模式。它的目的就是为了创建的类在当前进程中只有一个实例。
从定义可以看出,使用单例模式的目的无非就是下面两个:
这种方式不是单例模式,但可以满足需求,在正式生产中也会经常用到。
public static class SingletonSample1
{
private static int _counter = 0;
public static int IncreaseCount()
{
return ++_counter;
}
}
注意:这里的++_counter
其实存在高并发问题,严格上应该用Interlocked.Increment(ref _counter)
的方式,由于我们主要讲的是单例模式并且简单且能演示效果,所以故意忽略了这一点。下同
这是最简单的一种单例模式,也是比较常用的一种方式,可在正式生产中使用。
public sealed class SingletonSample2
{
private static readonly SingletonSample2 _instance = new SingletonSample2();
private int _counter = 0;
private SingletonSample2() { }
public static SingletonSample2 Instance
{
get
{
return _instance;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
以上两种方式都存在第一次加载时,资源浪费的问题,但在内存资源越来越便宜的今天,通常这种浪费是可以接受的,因此也不必过于纠结这种浪费。当然,在条件允许的情况下,能优化还是要优化的。
该方式是改进过程中的过渡阶段,不可用于生产。
public class SingletonSample3
{
private static SingletonSample3 _instance;
private int _counter = 0;
private SingletonSample3() { }
public static SingletonSample3 Instance
{
get
{
if (_instance == null)
{
_instance = new SingletonSample3();
}
return _instance;
}
}
public int IncreaseCount()
{
return ++\_counter;
}
}
该方式也是改进过程中的过渡阶段,不可用于生产。
public class public class SingletonSample4
{
private static SingletonSample4 _instance;
private static readonly object _locker = new object();
private int _counter = 0;
private SingletonSample4() { }
public static SingletonSample4 Instance
{
get
{
lock (_locker)
{
if (_instance == null)
{
_instance = new SingletonSample4();
}
return _instance;
}
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
注意:视频中讲到这里时,我其中有提到热启动关键词,我把系统预热口误说成了热启动,由于这两个概念之间有较大的差别,所以这里纠正一下。
著名的双检锁模式,完美解决问题,可用于生产。
public class SingletonSample5
{
private static volatile SingletonSample5 _instance;
private static readonly object _locker = new object();
private int _counter = 0;
private SingletonSample5() { }
public static SingletonSample5 Instance
{
get
{
if (_instance == null)
{
lock (_locker)
{
if (_instance == null)
{
_instance = new SingletonSample5();
}
}
}
return _instance;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
注意:volatile
是必须的,因为它可以保证new
不会被指令重排序,详细可看视频部分的分析。
.Net支持的一种优雅版本的实现方式,前面讲了那么多其实就是为了引出该方式,强烈建议使用该版本。
public class SingletonSample6
{
private static readonly Lazy<SingletonSample6> _instance
= new Lazy<SingletonSample6>(() => new SingletonSample6());
private int _counter = 0;
private SingletonSample6() { }
public static SingletonSample6 Instance
{
get
{
return _instance.Value;
}
}
public int IncreaseCount()
{
return ++_counter;
}
}
泛型版本,是否使用视情况而定。
public class SingletonSampleBase<TSingleton> where TSingleton : class
{
private static readonly Lazy<TSingleton> _instance
= new Lazy<TSingleton>(() => (TSingleton)Activator.CreateInstance(typeof(TSingleton), true));
protected SingletonSampleBase() { }
public static TSingleton Instance
{
get
{
return _instance.Value;
}
}
}
public class SingletonSample7 : SingletonSampleBase<SingletonSample7>
{
private int _counter = 0;
private SingletonSample7() { }
public int IncreaseCount()
{
return ++_counter;
}
}
单例模式实现方式如此之多,但实际上大多数情况需要使用单例的时候都可以用静态类实现,比如一些工具类,而其他场景直接用单例模式五或者单例模式六即可,著名的双检索其实也是大可不必的,毕竟跟单例模式五相比,体现不出任何优势,还更容易出错。
原文:https://www.cnblogs.com/FindTheWay/p/13559259.html