单例模式的定义
单例模式保证一个类在全局中只有一个实例对象。
单例模式的几种实现方式
饿汉模式
在类加载的时候就已经实例化对象,没有延迟加载,但由于类加载的机制能保证线程安全,典型的空间换时间;
饿汉模式懒汉模式
只有在调用getInstance()的时候才会实例化对象,但需要加上synchronized关键字保证线程安全,具有延迟加载的功能,
典型的时间换空间,与饿汉相比会比较消耗性能。
DCL双重检查模式
懒汉模式的改进版,主要有两个地方的改进:同步锁改进和线程安全改进
同步改进:采用了双重检查的模式,第一层检查避免了不必要的加锁同步;第二层检查保证实例为null时才会初始化实例对象;
线程安全改进:实例变量采用了volatile关键字声明,volatile的语义能禁止指令重排序;在JVM中有一种优化机制叫乱序执行,也就是说为了执行效率,CPU可能不会按照代码的顺序执行,但是最终的执行结果跟代码顺序执行的结果是一致的。在这里volatile主要是解决DCL模式失效的问题,因为在new Singleton()初始化对象时不是一个原子操作,主要有三步:
(1)为实例变量分配内存;
(2)调用构造函数;
(3)实例变量执行已经分配的内存地址;
如果CPU乱序执行的话,有可能会按(1)(3)(2)的顺序执行,如果此时有线程A和线程B,线程A执行完了(3)还未执行(2)之前,切换到了线程B,那么此时线程B获得的实例就是非null的,线程B就直接返回该未初始化完成的实例对象,导致DCL失效。
静态内部类
其实就是饿汉模式的改进版本,增加了延迟加载的功能。不会在类加载的时候就实例化对象,只有在调用getInstance()的时候才会实例化,同时由于内部类加载的方式可以保证线程安全,写起来也比较简单。
静态内部类补充
1、单例的构造函数必须声明为private,保证不会被外界通过new的方式进行实例化;
网友评论