单例模式
在当前进程中,通过单例模式创建的类有且只有一个实例。
特点:
1. 保证在一个JVM中,该对象只有一个实例存在
2. 构造器必须是私有的,外部类无法通过调用构造器方法创建该实例
3. 没有公开的set方法,外部类无法调用set方法创建该实例
4. 提供一个公开的get方法获取唯一的这个实例
优点:
1. 减少系统开销,减低内存使用频率
2. 避免对资源的重复占用
饿汉模式
把对象提前实例化,外部第一次获取这个类的对象时就直接存在这个类,省去创建的开销
//饿汉模式
class HungrySingleton{
    //1.私有构造函数,保证不能实例化本类
    private HungrySingleton(){}
    //2. 创建一个类的实例化对象
    private static HungrySingleton hungrySingleton = new HungrySingleton();
    //3. 创建一个get方法,返回一个实例
    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}
懒汉模式
对象没有被提前实例化,外部第一次获取这个类的对象时是空的,需要初始化,赋值
线程不安全的模式
多个线程调用getInstance方法来获取Singleton的实例是,可能会导致实例化了两个对象
// 懒汉模式
class LazySingleton{
    //1.私有构造函数,保证不能实例化本类
    private LazySingleton(){}
    //2. 自己创建一个类的实例化 
    private  static LazySingleton singleton;
    //3. 创建一个get方法,返回实例
    public static LazySingleton getInstance(){
        //判断singleton是否为null,如果为null,即判定需要实例化
        if (singleton == null) {
            singleton= new LazySingleton();
        }
        return singleton;
    }
}
线程安全模式
// 懒汉模式
class LazySingleton{
    //1.私有构造函数,保证不能实例化本类
    private LazySingleton(){}
    //2. 自己创建一个类的实例化 (volatile保证不会发生重排序)
    private volatile static LazySingleton singleton;
    //3. 创建一个get方法,返回实例
    public static LazySingleton getInstance(){
        //判断singleton是否为null,如果为null,即判定需要实例化
        if (singleton == null) {
            //同步块,线程安全的创建实例
            synchronized (LazySingleton.class){
               // 再次检测实例是否存在
               if (singleton == null){
                   singleton= new LazySingleton();
                    // 字节码层
                    //JIT 即时编译 CPU
                    //1. 分配空间
                    //2. 初始化
                    //3. 引用赋值
                }
            }
        }
        return singleton;
    }
volatile的作用:
1. 防止指令重排序,对象的实例化包含创建和赋值
2. 保证内存可见,volatile修饰的变量,不会被本地缓存,所有线程对该对象的读写都会第一时间同步到主内存。
懒汉模式和饿汉模式的区别
两者的根本区别在于对象是否别提前实例化,以及线程的安全问题