文章目录
一、如何高效实现单例(Sinleton)设计模式
单例模式的基本概念
单例模式的不同实现方式及各自优势
饿汉式
懒汉式
懒汉式 + synchronized
懒汉式+Double Check
实际上不是线程安全的,instance() = new Singleton();可以分解成以下4个步骤
Volatile
对原始类型的读写都是原子类型的
long、double的读写不是原子类型的,加上volatile可以让它有原子性
volatile不保证对变量的加减操作是原子类型的,可以使用原子变量做到
当一个线程写了volatile变量之后可以立刻把这个变量刷新到主存去,让其他变量可以看到,不是放在缓存空间等一段才能看见。
禁止指令重排序
懒汉式+Double Check + Volatile
这里volatile的作用除了有序性,是不是可见性也需要volatile来保证呢?
没有,这里不需要volatile来保证可见性,有synchronized加上锁保证可见性。假如没有volatile,第二个线程拿到锁才能看到,第一个线程解锁,第二个线程加锁,如果第一个线程做了修改,第二个线程可以看见。即使没有volatile也可以保证可见性。
内部类Holder
实现了和double check 一样的功能,更加简洁。
单例模式实现的问题
枚举(Enum)
和饿汉式一样,加载时初始化,不是延迟初始化。可以抵抗反序列化工具和反射工具,对于枚举类型的反序列化,JVM有特别规定,要求反序列化只返回枚举类型的名字,到虚拟机里面再通过valueOf名字去构建一个新的实例,如果这个实例已经在了就把他构建,如果没在就构建一个新的实例,保证实例的唯一性。通过反射方法获取私有的构造函数,通过反射调用new instance时会报错,new instance会判断类型是不是枚举类型,如果是枚举类型就会报错。