单例模式 一、什么是单例模式 二、特点 三、应用场景 四、实现方式

一个类有且仅有一个实例,并且自行实例化向整个系统提供。

二、特点

 1、单例类只能有一个实例。
 2、单例类必须自己创建自己的唯一实例。
 3、单例类必须给所有其他对象提供这一实例。

三、应用场景

控制实例数目,节省系统资源的时候,例如线程池、缓存、日志对象等,或用于计数。

四、实现方式

  1. 饿汉式
//饿汉式
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}  

//ps: 类加载时就创建对象,所以会导致类加载变慢。若不使用这个实例,则相当于浪费内存。
// 也正因为类加载时创建,保证了线程安全

//饿汉式-第二种写法
public class Singleton {  
    private Singleton instance = null; 
    static{
    instance=new Singleton();
    } 
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}  
//ps: 与第一种实现过程一致

2.懒汉式

//懒汉式-基础版
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  //私有构造函数,无法从外部获取
    public static Singleton getInstance() {  //静态实例,创建对象
    if (instance == null) { 
        instance = new Singleton();  
    }  
    return instance;  
    }  
}  
//ps: 实现了类加载时不创建实例,而是在调用时创建实例,有效的避免了内存的浪费。
// 但是,此种方式不能保证线程安全,所以仅适用于单线程

//懒汉式-加锁版
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
} 
//ps: 在基础版的基础上实现了线程安全,但在方法上加锁会影响效率。即:如果频繁的调用getInstance()方法,会频繁的加锁。

//懒汉式-加锁版2
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static Singleton getInstance() {  
    if (instance == null) {  
        synchronized (Singleton.class) {
            instance = new Singleton();  
        }
    }  
    return instance;  
    }  
} 
//ps: 摒弃了同步方法改为同步实例化代码块,虽然效率提高了,但又出现了线程安全问题。

//懒汉式-加锁版2优化:双重校验
public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}  
//ps: 进行两次实例判空操作,实现线程安全。采用volatile关键字,volatile可以保证即使Java虚拟机对代码执行了指令重排序,也会保证它的正确性。
// 推荐使用

3.静态内部类实现

//静态内部类
public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}   
//ps: 这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。
// 这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

4.枚举实现

public class EnumSingleton{
    private EnumSingleton(){}
    public static EnumSingleton getInstance(){
        return Singleton.INSTANCE.getInstance();
    }
    
    private static enum Singleton{
        INSTANCE;
        
        private EnumSingleton singleton;
        //JVM会保证此方法绝对只调用一次
        private Singleton(){
            singleton = new EnumSingleton();
        }
        public EnumSingleton getInstance(){
            return singleton;
        }
    }
}
//ps: 简洁,自动支持序列化机制,绝对防止多次实例化。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象