单例模式——小结

142 阅读3分钟

一、什么是单例模式

一个类中,有且只有一个实例,这种类叫做单例。这种设计模式也被称之为单例模式。 另一种说法即:当前进程中,单例模式创建的实例有且只有一个。

二、为什么不用静态方法而用单例模式?

两者其实都能实现我们加载的最终目的,但是他们一个是基于对象,一个是面向对象的,就像我们不面向对象也能解决问题一样,面向对象的代码提供一个更好的编程思想。

所以我们用单例模式或静态方法去维持一份这些值有且只有这一份值,但此时这些配置和属性又是通过面向对象的编码方式得到的,我们就应该使用单例模式,或者不是面向对象的,但他本身的属性应该是面对对象的,我们使用静态方法虽然能同样解决问题,但是最好的解决方案也应该是使用单例模式。

另外单例模式支持延迟加载,可以避免资源浪费。

三、单例模式有哪几种表现形式

1)、饿汉式

类加载的时候,实例就被初始化加载。JVM保证其唯一性与安全性。

注:JVM的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的

2)、懒汉式

懒汉式支持延迟加载,但需注意线程安全问题。

注:有一定的不安全性,如用到的情况下,要尽量使用双检锁进行延迟加载。

对象要volatile声明,不然也会出现重排序问题。

3)、静态内部类

类似饿汉式,但又可实现延迟加载的情况。JVM保证其唯一性与安全性。

注:JVM的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的

4)、枚举单例

类似饿汉式

写法简洁,代码短小精悍。

线程安全。

防止反序列化和反射的破坏。

四、为什么说枚举是单例模式的最好实现

因为枚举写法简洁,同时能保证线程安全与被破坏的风险。

五、多例实现

多例模式很像工厂模式,它跟工厂模式的不同之处是,多例模式创建的对象都是同一个类的对象,而工厂模式创建的是不同子类的对象

六、概述什么是指令重排序

指令重排序指的是JIT编译器、cpu处理器和jmm定义的多级缓存存储,在编译字节码和运行机器指令时,在不影响程序最终执行结果的情况下,会对原语句执行的顺序进行优化。jmm多级缓存会让语句的执行并不一定是按照正确的读写操作进行的。但是这些都是jmm所允许的操作。因此需要通过同步来禁止相关的指令重排序,如内存屏障。

举例: Demo instance = new Demo(); 并不是一个原子操作,其在JVM中至少做了三件事:

给instance在堆上分配内存空间。(分配内存)

调用DoubleCheckIdGenerator的构造函数等来初始化instance。(初始化)

将instance对象指向分配的内存空间。(执行完这一步instance就不是null了)

在没有volatile修饰时,执行顺序可以是1,2,3,也可以是1,3,2。假设有两个线程,当一个线程先执行了3,还没执行2,此时第二个线程来到第一个check,发现instance不为null,就直接返回了,这就出现问题,这时的instance并没有完全完成初始化。