单例定义
单例模式(Singleton Design Pattern),一个类只允许创建一个对象(或者实例),那这个类就时一个单例类,这种设计模式就时单例模式
单例的几种实现
1、饿汉式
饿汉式的实现方式是在类加载的时候,instance静态实例已经创建并初始化好了,这种方式是线程安全的,但是并不支持延迟加载,也就是不能在用到的时候再去创建实例
public class SingletonTest {
private static SingletonTest instance = new SingletonTest();
private SingletonTest (){}
public static SingletonTest getInstance() {
return instance;
}
}
这种方式因为不支持延迟加载,如果实例占用资源多或者初始化耗时时间长的话,我们就可以把这个耗时长的初始化过程提前到程序启动的时候完成,这样可以避免我们在真正调用这个实例的时候再去执行初始化,这会影响到系统的性能,同时,如果占用的资源过多,也会再程序初始化的时候出发报错,比如OOM,我们可以去立即修复,否则当程序跑起来了,突然因为初始化这个实例需要大量的资源,导致系统崩溃,那就凉凉了。这就涉及到是以时间换空间,还是以空间换时间的问题思考了
2、懒汉式
懒汉式相对于饿汉式的优势是支持延迟加载
public class SingletonTest {
private static SingletonTest instance;
private SingletonTest (){}
public static synchronized SingletonTest getInstance() {
if(instance == null){
instance = new SingletonTest();
}
return instance;
}
}
懒汉式中,给getInstance()加了把锁,这就导致这个函数如果在被频繁调用的时候,频繁的加锁、释放锁以及并发度的问题会导致性能瓶颈
3、双重检测
这种方式相等于解决了饿汉式和懒汉式的缺点,由于饿汉式不支持延迟加载,而懒汉式有性能问题,不支持高并发,所以就有了双重检测的实现方式;这种实现方式,只要instance被创建之后,即便再调用getInstance()函数也不会再进入加锁逻辑中了
public class SingletonTest {
private static volatile SingletonTest instance;
private SingletonTest (){}
public static SingletonTest getInstance() {
if(instance == null){
synchronized (SingletonTest.class){ // 此处为类级别的锁
if(instance == null){
instance = new SingletonTest();
}
}
}
return instance;
}
}
双重检测的原理是:线程A,线程B,先后执行get方法,进行对象为空的判断,A线程争抢到锁资源,进行实例化对象,并进行赋值,逻辑处理,当该线程执行完实例化对象后,其他线程抢到锁资源,如果不进行一次对象为空判断,那就会再次创建一个该类的实例化对象。
这里instance 成员变量上加了volatile关键字,可以禁止指令重排序,但是我看到有的大佬说可以不加这个关键字,因为高版本的java已经在jdk内部实现中解决了这个问题,关于这个问题,可以找个时间研究一下
4、静态内部类
这种方式比双重校验要简单一些,就是利用静态内部类,类似于饿汉式,但是又做到了延迟加载
public class SingletonTest {
private static volatile SingletonTest instance;
private SingletonTest (){}
private static class SingletonHolder{
private static final SingletonTest instance = new SingletonTest();
}
public static SingletonTest getInstance(){
return SingletonHolder.instance;
}
}
SingletonHolder是一个静态内部类,当调用getInstance()方法时,才会被加载,这个时候才会创建instance。instance的唯一性、创建过程的线程安全都由JVM来保证。所以,这种实现方式即保证了线程安全,又能做到延迟加载
5、枚举
这种方式通过java枚举类型本身的特性,保证了实例创建的线程安全和唯一性
public enum Singleton {
INSTANCE;
}