单例设计模式
单例设计模式,简单来说就是一个类只能创建一个对象实例。
单例模式它有几个要素:
1、私有的构造方法;
2、指向自己实例的私有静态引用;
3、以自己实例为返回值的静态公有方法;
单例模式分类:
1、懒汉模式:实例在第一次使用时创建;
2、饿汉模式:实例在类装载时创建;正因为这种特性,因此在多线程环境下,不会出现问题;
因为懒汉模式在多线程环境下,有可能会出现创建多个实例,因此下面我们由浅入深一步一步解决问题。
懒汉模式有普通方式和静态内部类方式。
A、普通方式
方式1:
该方式在单线程环境下没有问题,但是多线程下会出现创建多个实例的问题。
方式2:
该方式在获取实例的方法中添加一个同步锁,来解决创建多个实例的问题。但是这种方式的弊病在于会强制让除当前进入线程以外的其他线程等待,效率低。(ps:如果不理解,请往下看)
方式3:双重检查(DCL)
说明:
(1)第一个if(instance == null)通过减少线程进入同步代码块的概率,来减少需要等待的线程数来解决效率低的问题;
(2)第二个if(instance == null)目的是防止创建多个实例的发生;
方式4:
JVM在执行instance = new Singleton()时,做了下面3个操作:
1:给instance分配内存;
2:调用构造方法Singleton()来初始化成员变量,形成实例;
3:将实例指向已分配的内存;
由于该句并非原子操作,因此JVM的即时编译器会执行指令重排序操作。这样可能导致执行顺序并不是1->2->3。在多线程环境下有可能出错。
为了解决上述的问题,给instance声明时加上volidate来禁止重排序。
B、静态内部类
在SingletonHolder初始化的时候会由ClassLoader来保证同步,使INSTANCE是一个真实例。从内部来看是一个饿汉式的单例,但是从外部来看又是懒汉式。这个是不是有点矛盾吗?