持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
本文系作者 不太自律的程序猿原创,转载请私信并在文章开头附带作者和原文地址链接。
单例设计模式
定义:保证一个类只有一个实例,并且提供一个全局访问点
场景:重量级的对象,不需要多个实例,如线程池,数据库连接池。
实现方式:
1.饿汉模式(先创对象)
2.懒汉模式(后创对象)
饿汉模式
饿汉模式是:直接创建实例对象,不管你是否需要这个对象都会去创建
public HungrySingleton{
private static HungrySingleton instance = new HungrySingleton() ;//属性私有化
private HungrySingleton(){
//构造函数私有化
}
public HungrySingleton getHungrySingleton(){
//提供共有的方法
return instance;
}
}
懒汉模式
懒汉模式是:类加载时没有创建实例,使用时才会去创建该对象,延迟加载
我们逐步的去实现并思考每次代码实现之后是否存在BUG。
不能实现单例
public LazySingleton{ private LazySingleton instance;//属性私有化 private LazySingleton(){ //构造函数私有化 } public LazySingleton getLazySingleton(){ //提供共有的方法 //判断lazySingleton为空的时候我们再去创建 if(instance==null){ instance = new LazySingleton(); } return instance; } }现状:此时的代码在多线程中不能实现单例。
解决方案:所以我们可以将getLazySingleton()方法添加synchronized关键字修饰整个方法。但是这样性能会下降很多。
单线程安全的懒汉式
public LazySingleton{ private LazySingleton instance;//属性私有化 private LazySingleton(){ //构造函数私有化 } public synchronized LazySingleton getLazySingleton(){//提供共有的方法 //判断lazySingleton为空的时候我们再去创建 if(instance==null){ instance = new LazySingleton(); } return instance; } }现状:此时的代码在多线程中能够实现单例,但是因为getLazySingleton()方法添加synchronized关键字修饰,导致方法性能很低。
解决方案:将synchronized放到getLazySingleton方法内部,去修饰代码块,提升性能。
DCL双重检查锁机制 (DCL:double checked locking)
public LazySingleton{ private LazySingleton instance;//属性私有化 private LazySingleton(){ //构造函数私有化 } public LazySingleton getLazySingleton(){//提供共有的方法 //判断lazySingleton为空的时候我们再去创建 if(instance==null){ synchronized(LazySingleton.class){ //多线程等待所释放的时候,如果不加判断,会创建多次,所以需要在加一次判断。 if(instance==null){ instance = new LazySingleton(); //字节码层 //JIT ,CPU //1、分配空间 //2、初始化 //3、引用赋值 //如果指令重排序 //1、分配空间 //3、引用赋值 // 执行到这的时候lazySingleton已经不为null,因为已经指向了对应的空间地址,那么另一个线程此时获取到的lazySingleton并没有实际的值 //2、初始化 } } } return instance; } }现状:此时的代码在多线程中能够实现单例,也通过synchronized修饰代码块的方式,双重判断提高了性能,但是在多CPU情况下内部还是存在指令重排序的问题。
解决方案:使用volatile关键字防止指令重排序。
最终版本:
public LazySingleton{ private volatile LazySingleton instance;//属性私有化 private LazySingleton(){ //构造函数私有化 } public LazySingleton getLazySingleton(){//提供共有的方法 //判断lazySingleton为空的时候我们再去创建 if(instance==null){ synchronized(LazySingleton.class){ //多线程等待所释放的时候,如果不加判断,会创建多次,所以需要在加一次判断。 if(instance==null){ instance = new LazySingleton(); } } } return instance; } }
感谢诸君的观看,文中如有纰漏,欢迎在评论区来交流。如果这篇文章帮助到了你,欢迎点赞👍关注。