单例模式在现实开发中几乎无所不在,数据库建立连接,iOC创建对象,winfrom创建窗口,读取配置文件等等。
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
实现单利模式的原则和过程:
1.单例模式:确保一个类只有一个实例,自行实例化并向系统提供这个实例
2.单例模式分类:饿单例模式(类加载时实例化一个对象给自己的引用),懒单例模式调用取得实例的方法如getInstance时才会实例化对象)
3.单例模式要素:
a.私有构造方法
b.私有静态引用指向自己实例
c.以自己实例为返回值的公有静态方法
1.饿汉式:单例实例在类装载时就构建,急切初始化。(预先加载法)
/** * 饿汉式 * */ public class Test { private Test() { } public static Test instance = new Test(); public Test getInstance() { return instance; } }
优点
1.1.线程安全
1.2.在类加载的同时已经创建好一个静态对象,调用时反应速度快
缺点
资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化
2.懒汉式:单例实例在第一次被使用时构建,延迟初始化。
class Test { private Test() { } public static Test instance = null; public static Test getInstance() { if (instance == null) { //多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况 instance = new Singleton2(); } return instance; } }
优点:
避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。
缺点:
懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。
3.双重检测 其实就是懒汉模式的升级版
class Test { private Test() { } public static Test instance = null; public static Test getInstance() { if (instance == null) { synchronized (Test.class) { if (instance == null) { instance = new Test(); } } } return instance; } }
优点
资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法 ,弥补了懒汉模式下的多线程下的安全。
缺点
第一次加载时反应不快,多次判断效率低一点
4.静态初始化 由于是在自己被加载时就已经实例化,所以 这种也是属于饿汉式
public sealed class Test { private Test() { } public static readonly Test instance = new Test(); public static Test GetInstance() { return instance; } }
优点
线程安全,写法简单。
缺点
资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化