单例模式详解
一.单例模式的特点
1.保证JVM内存中只有一对象实例,且实例只能被创建一次.
2.对象实例只能由单例类自身创建,不能由其他对象创建.
3.没有接口,不能被继承.
二.使用场景
1.创建应用中的全局对象.
2.WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来.
3.创建新建时占用资源多且可重复使用的对象,如I/O连接,数据库连接等.
三.实现方式
1.饿汉模式
/** * @date 2020-6-11 * @description 饿汉模式 * 特点: * 1.在类加载的时候就创建实例,即使不被使用,仍旧存在实例,所以会产生垃圾对象 * 2.线程安全 */ public class SingleDemo1 { private static SingleDemo1 singleDemo1 = new SingleDemo1(); private SingleDemo1() {} public static SingleDemo1 getInstance() { return singleDemo1; } }
2.懒汉模式
/** * @date 2020-6-11 * @description 懒汉模式 * 特点: * 1.在调用实例获取方法的时候创建实例 * 2.线程不安全,并发调用实例获取方法时,可能或导致重复创建 */ public class SingleDemo2 { private static SingleDemo2 instance = null; private SingleDemo2() {} public static SingleDemo2 getInstance() { if(instance == null) { instance = new SingleDemo2(); } return instance; } }
3.volatile和双重检测的懒汉式
/** * @date 2020-6-11 * @description volatile + 双重检测的懒汉式 * 特点: * 1.依旧采用懒加载方式获取实例 * 2.使用volatile修饰成员变量,保证成员变量并发下的线程可见性,同时防止CPU进行指令重排 * 3.使用synchronized加锁,保证并发下只有一个线程可以创建实例 * 4.线程安全 */ public class SingleDemo3 { private volatile static SingleDemo3 instance = null; private SingleDemo3() {} public static SingleDemo3 getInstance() { if(instance == null) { synchronized (SingleDemo3.class) { if(instance == null) { instance = new SingleDemo3(); } } } return instance; } }
4.枚举方式
/** * @author Fansr * @date 2020-6-11 * @description 枚举方式 * 1.在JVM只会初始化一次,枚举本身创建就是单例的 * 2.线程安全 * 3.自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化 * java.lang.Enum<T> * */ public class SingleDemo4 { public static void main(String[] args) { SingleEnum instance1 = SingleEnum.INSTANCE; SingleEnum instance2 = SingleEnum.INSTANCE; System.out.println(instance1 == instance2); } private enum SingleEnum { INSTANCE; public void print() { System.out.println("SingleEnum"); } } }
5.静态内部类方式
/** * @date 2020-6-11 * @description 静态内部类方式 * 特点: * 1.利用了静态内部类的类加载机制,类只能被加载一次 * 2.线程安全 * 3.实现懒加载 * 静态内部类类加载说明: * 1.JVM中,无论是外部类还是内部类或是静态内部类都只能被加载一次. * 2.外部类在加载时,首先会依次初始化静态变量,静态代码块,静态方法,但不会加载内部类或是静态内部类. * 3.静态内部类在被调用时才会加载,且只加载一次. * 4.外部类和静态内部类的加载是分开的,加载不会相互影响. */ public class SingleDemo5 { private static class SingletonHolder { public static final SingleDemo5 INSTANCE = new SingleDemo5(); } private SingleDemo5 (){} public static final SingleDemo5 getInstance() { return SingletonHolder.INSTANCE; } }