单例模式
定义:单例模式顾名思义就是只有一个对象被创建,大家全部共享这个对象
分类:常见的单例模式分为饿汉式、懒汉式、双重校验锁、静态内部类和枚举五种
单例模式详解
一、饿汉式
缺点:单例没有用到也会被创建,而且在类加载之后就被创建,内存浪费
demo示例:
/**
* 饿汉式单例
*
* @author supu
* @date 2019-06-20 14:35
**/
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
二、懒汉式
demo示例:
/**
* 懒汉式单例
*
* @author supu
* @date 2019-06-20 14:35
**/
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
三、双重校验锁
Java中的指令重排优化。所谓指令重排优化是指在不改变原语义的情况下,通过调整指令的执行顺序让程序运行的更快。JVM中并没有规定编译器优化相关的内容,也就是说JVM可以自由的进行指令重排序的优化。
这个问题的关键就在于由于指令重排优化的存在,导致初始化Singleton和将对象地址赋给instance字段的顺序是不确定的。在某个线程创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。若紧接着另外一个线程来调用getInstance,取到的就是状态不正确的对象,程序就会出错
优点:使用volatile关键字禁止指令重排序优化,保证了instance变量被赋值的时候对象已经是初始化的。即实现了延迟加载,又解决了线程并发问题,同时还解决了执行效率问题
demo示例:
/**
* 双重校验锁单例
*
* @author supu
* @date 2019-06-20 14:35
**/
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
四、静态内部类
优点:利用类加载机制(避免了线程并发问题)来保证只创建一个实例,使用内部类时才会创建单例,这样达到了延迟加载的效果
demo示例:
/**
* 静态内部类单例
*
* @author supu
* @date 2019-06-20 14:35
**/
public class Singleton {
private static class SingletonHolder {
public static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
1、需要额外的工作来实现序列化,否则每次反序列化一个序列化的对象时都会创建一个新的实例
2、可以使用反射强行调用私有构造器(如果要避免这种情况,可以修改构造器,让它在创建第二个实例的时候抛出异常)
原因:单例一旦实现了序列化接口,那么它们就不在保持单例了,因为readObject()方法一直返回一个新的对象(就像java的构造方法一样)
解决方法:你可以使用readResolve()方法来避免此事发生,实例如下:
但是如果你的单例类中还引用其他对象的状态的话,就需要使用transient关键字修饰引用对象
五、枚举
优点:枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象
demo示例:
/**
* 枚举单例
*
* @author supu
* @date 2019-06-20 14:35
**/
public enum Singleton {
INSTANCE;
public static Singleton getInstance() {
return INSTANCE;
}
}