简单纪要:单例模式的几种创建方式,看这一篇就够了
单例介绍:
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此有些设计大师并把把其称为设计模式之一。
应用:
1、多线程的线程池的设计一般是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
2、Spring框架中对象的创建,默认也是单例的,这样可以简化资源,每次请求访问的都是同一个对象。
2、Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
3、网站的计数器,一般也是采用单例模式实现,否则难以同步。
4、应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
5、数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
有了基本的了解以后,我们来看单例的第一种实现;
单例之饿汉模式:
代码实现:
/** * Created by Rnan on 2022/4/9. */ public class SingletonHungry{ // 直接进行对象的初始化 private static final SingletonHungry singletonLazy = new SingletonHungry(); // 私有化构造器,不允许通过构造器创建 private SingletonHungry(){ } // 开放唯一获取对象的接口 public static SingletonHungry getInstance(){ return singletonLazy; } }
注意:
1、饿汉模式就是,不管以后使用与否,直接就是new一个对象,如果对应一直未被调用,对应的对象也已创建成功,可以保证百分百的单例,对象不会被实例化多次;
2、构造方法用private修饰,保证只有他自己可以实例化这个对象,别人不能操作。
单例之懒汉模式:
代码实现(同步方法):
/** * Created by Rnan on 2022/4/9. */ public class SingletonLazy{ private static SingletonLazy singletonLazy = null; private SingletonLazy() { } public static synchronized SingletonLazy getInstance(){ if(singletonLazy == null){ singletonLazy = new SingletonLazy(); } return singletonLazy; } }
注意:
同步方法也可以百分百的保证单例,但是由于synchronized的排他性,会导致该方法性能过低。
单例之DCL:
代码实现(双端检索版本):
/** * Created by Rnan on 2022/4/9. */ public class SingletonLazy{ private static SingletonLazy singletonLazy = null; private SingletonLazy() { } public static SingletonLazy getInstance(){ if(singletonLazy == null){ synchronized (SingletonLazy.class){ if(singletonLazy == null){ singletonLazy = new SingletonLazy(); } } } return singletonLazy; } }
注意:
1、双端检锁是一种比较好的创建单例的方法,在对象为null的时候,只让一个线程去创建对象,其他线程直接获取对象即可;
2、当两个线程同时发现对象为null,只让一个线程进入同步代码块,完成对象的初始化,随后的线程如果再次进入同步代码块,发现对象已经被初始化,就直接返回对象的实例,不再进行创建,这是未加载情况下并行的场景,如果对象加载完成,直接再第一个判断为null的地方,就直接获取初始化好的对象了,不会进入同步代码块,提高性能;
问题:
这种方式看似无懈可击,但是由于操作系统的指令重排,会导致空指针异常;
单例之volatile + DCL:
代码实现(volatile + 双端检索版本):
/** * Created by Rnan on 2022/4/9. */ class SingletonLazy{ private static volatile SingletonLazy singletonLazy = null; private SingletonLazy() { } public static SingletonLazy getInstance(){ if(singletonLazy == null){ synchronized (SingletonLazy.class){ if(singletonLazy == null){ singletonLazy = new SingletonLazy(); } } } return singletonLazy; } }
注意:
1、singletonLazy = new SingletonLazy(); 这行代码在指令级别对应的三步操作
第一步:memory = allocate(); //1.分配对象内存空间
第二步:instance(memory);//2.初始化对象
第三步:nstance = memory;//3.设置instance指向刚分配对象的内存地址,这个时候instance != null;
如果第三步先于第二步执行,就会出现空指针问题;
2、volatile 的特性之一就是,禁止指令重排,能够禁止操作系统对指令进行优化,在多线程下保证线程安全;
单例之静态内部类:
代码实现(静态内部类):
/** * Created by Rnan on 2022/4/9. */ public class Singleton { private static class SingletonInno{ public static SingletonInno instance = new SingletonInno(); } public static SingletonInno getInstant(){ return SingletonInno.instance; } }
注意:
在内部类直接进行实例化,使用饿汉式进行加载,但这也并不完全是饿汉式,因为静态类不会主动加载,只有在主类被调用的时候,才会被加载,保证程序运行时不会提前创建对象而浪费内存,只有主动调用时,才创建实例,保证懒加载;
单例之枚举:
代码实现(枚举):
/** * Created by Rnan on 2022/4/9. */ enum SingletonEnum{ INSTANT; public static SingletonEnum getInstance(){ return INSTANT; } }
注意:
1、枚举不允许被继承,所以线程安全只能被初始化一次;
2、但是使用枚举不能被懒加载,只要调用静态方法,直接实例化对象;
以上就是单例模式的所有创建方法,感兴趣的小伙伴可以自己敲敲,有问题可以评论沟通,see you again!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)