为什么要用单例模式?
1、单例模式节省公共资源
比如:大家都要喝水,但是没必要每人家里都打一口井是吧,通常的做法是整个村里打一个井就够了,大家都从这个井里面打水喝。
对应到我们计算机里面,像日志管理、打印机、数据库连接池、应用配置。
2、单例模式方便控制
就像日志管理,如果多个人同时来写日志,你一笔我一笔那整个日志文件都乱七八糟,如果想要控制日志的正确性,那么必须要对关键的代码进行上锁,只能一个一个按照顺序来写,而单例模式只有一个人来向日志里写入信息方便控制,避免了这种多人干扰的问题出现。
Spring框架应用中的 ApplicationContext就是单例模式中的饿汉式
写法
饿汉模式(线程安全)
缺点:类加载的时候就初始化,不管用不用都占内存空间
public class Singleton { //确保对象实例只有一个。 private static final Singleton singleton = new Singleton(); //构造方法私有 private Singleton() {} //以静态方法返回实例 public static Singleton getInstance() { return singleton; } }
懒汉模式
基于双重检查锁实现线程安全,性能不如静态内部类,但是可以传构造参数
public class SingleTon{ /** * volatile 关键字可以保证线程间变量的可见性,还有一个作用就是阻止局部重排序的发生 */ private volatile static SingleTon INSTANCE = null; private SingleTon(){} public static SingleTon getInstance(){ if(INSTANCE == null) { synchronized(SingleTon.class){ if(INSTANCE == null){ INSTANCE = new SingleTon(); } } return INSTANCE; } } }
基于静态内部类实现线程安全,性能比双重检查锁要好,缺点是无法传构造参数进来
public class Singleton { private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){ /*为了避免反射破坏单例,需要在构造方法中增加限制,一旦出现多次重复创建,直接抛出异常*/ if (null != LazyHolder.INSTANCE) { throw new RuntimeException("创建Singleton异常,不允许创建多个实例!"); } } /** * 调用静态方法的时候会先加载Singleton类,静态内部类只有在使用的时候才会被加载。 * 而ClassLoader加载的时候是单个线程的。所以既能够实现需要的时候才被加载,也能够实现线程安全。 */ public static final Singleton getInstance() { return LazyHolder.INSTANCE; } }