什么是单例模式(Singleton):
在程序中有些对象我只需要一个,比如说配置文件、工具类、日志、缓存、线程池等等对象;
当多个程序去调用一个配制文件的时候,实际上调用的是一个相同的配置文件,如果多个程序调用的是多个配置文件,那么每次修改文件,就会出现问题,这是不合理的,比如说可能导致占用过多资源,不一致等结果;
比如程序中的缓存日志等等我们只需要一个就可以了,我们如果想保证整个应用中某个实例有且仅有一个的话,我们就要使用到单例模式
应用场景:
当有些对象我们只需要一个就足够的时候,使用单例模式
作用:
保证整个程序中的某一个实例对象有且仅有一个
类型:
1.饿汉模式:
不管用户是否需要该对象,只要类加载了,就会去创建该单例模式的对象,即假设总是处于饥饿状态,所以就叫做饿汉模式
- public class Singleton {
- //1.将构造方法私有化,不允许外部直接创建对象
- //创建一个无参构造方法,并且把该构造方法设置为私有型
- //此步骤修改了默认的构造方法
- private Singleton(){}
- //2.在类的内部创建唯一实例,使用private static实现(因为1中把构造方法私有化了)
- //static:把它变成类的静态成员,外部才能调用
- //private:为了控制访问安全,需要把它变成私有的,不允许外部直接访问
- //当类被加载时,被static修饰的东西就要初始化,这就是饿汉模式的体现
- private static Singleton singletonInstance = new Singleton();
- //3.提供一个用于获取实例的方法,使用public static实现(因为2中把实例私有化了)
- //需要添加static变成类方法才能被外部调用;如果不添加static,它是对象,不是类方法,所以外部是访问不到的
- //根据面向对现象的封装性,创建一个静态公有的get函数,这样就能通过使用类名来直接获取该实例
- public static Singleton getSingletonInstance(){
- return singletonInstance;
- }
- }
2.懒汉模式:
当用户第一次使用的时候才创建,后面再使用就不需要创建了,只实例化一次,即假设它比较懒,使用才创建,不用不创建,而且只创建一次,所以叫做懒汉模式
测试代码: 区别:饿汉模式:加载类使比较慢(每次都要创建实例),但是运行时获得对象的速度比较快(因为在类加载的时候就已经实例化对象),线程安全
懒汉模式:加载类比较快(不需要创建实例),但是运行时获取对象的速度比较慢(因为每次都要去判断对象是否存在),线程不安全
懒汉模式中的线程安全问题:
从线程安全方面来考虑,不使用同步的懒汉模式是线程不安全的
举例:假如从线程A开始进入,判断singletonInstance为空,此时就会创建一个实例对象,
然后CPU进行切换,此时进来的是线程B,再对singletonInstance进行判断,依然为空,此时又会创建一个实例对象,
然后CPU又切换到线程A继续创建实例,这时就会初相见两个实例
所以为了安全的使用单例模式,要不选择使用饿汉模式在类加载时创建实例,要不就使用同步锁的懒汉模式
懒汉模式线程安全的代码:
使用的是双重检查锁定
要点总结:
1.单例模式确保程序中一个类最多只有一个实例;
2.单例模式也提供访问这个实例的全局点;
3.在Java中单例模式需要有私有构造器、一个静态方法、一个静态变量;
4.确定性能和资源上的限制,然后小心的选择适当的方案来实现单例,以解决多线程问题;
5.双重检查加锁需要再JDK1.5及其以后的的版本才有效果;
6.如果使用多个类加载器,可能导致单例失效而产生多个实例;
7.如果使用JVM1.2及其以前的版本,必须建立单例注册表,以免垃圾收集器将单例回收。