【一起学系列】之单例模式:只推荐三种~
2020/5/26 17:25:37
本文主要是介绍【一起学系列】之单例模式:只推荐三种~,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
别名:单件模式
单例模式的诞生
【开发】:老大,为什么我保存配置信息,每次都和我预期的不一样啊,总是会覆盖?
【BOSS】:哈?我来看看。
【BOSS】:你每次使用的时候都会new一个新的配置对象吗?
【开发】:对啊,有什么问题?
【BOSS】:那肯定不对啊,像这种配置信息,全局只应该有一个,不然会互相影响!
HeadFirst 核心代码
饿汉型 (不推荐)
public class HazardousTypeSingleton { private static final App APP = new App(); // 私有构造方法 private HazardousTypeSingleton () {} // 类加载时已初始化,不会有多线程的问题 static App getInstance() { System.out.println("APP - 饿汉型模式"); return APP; } } 复制代码
❝名字由来:因为随着类加载而加载,显得很“急迫”,所以称之为饿汉型
❞
**评价:**这样的写法和全局变量没有本质的区别,不推荐
懒汉型 (不推荐)
public class LazyTypeSingleton { private LazyTypeSingleton () {} // 静态私用成员,没有初始化 private static App intance = null; /*** * 直接加synchronized关键字 */ synchronized static App getIntance () { System.out.println("APP - 懒汉型模式"); if (null == intance) { intance = new App(); return intance; } return intance; } } 复制代码
❝名字由来:调用时才加载,因此称之为懒汉型
❞
**评价:**这样写有延迟加载的功能,但是加了一个synchronized大锁,因此多线程环境下效率较低
懒汉型之双重锁校验 🧡
public class LazyTypeSingleton { // volatile关键字修饰,防止指令重排 private volatile static App app = null; /*** * Double Check Lock(DCL) 双重锁校验 */ static App getInstanceByDCL () { if (null == app) { synchronized (LazyTypeSingleton.class) { if (null == app) { System.out.println("APP - 饿汉模式DCL 双重锁校验"); app = new App(); return app; } } } return app; } } 复制代码
❝注意volatile关键字起到的作用,详情请见:https://juejin.im/post/5ebadd9df265da7bda414c20
❞
**评价:**比较推荐的写法,可以保证线程安全,同时具备延时加载的效果
静态内部类方式🧡
public class InnterTypeSingleton { private InnterTypeSingleton(){ throw new IllegalStateException(); } // 静态内部类方式,类似饿汉保证天然的线程安全 private static class SingletonHolder{ private final static App app = new App(); } static App getInstance(){ System.out.println("APP - 静态内部类方式(Holder)"); return SingletonHolder.app; } } 复制代码
**评价:**线程安全,调用效率高,可以延时加载
静态内部类之神奇的报错
public class InnterTypeSingletonError { private InnterTypeSingletonError(){ System.out.println(5 / 0); } private static class SingletonHolder{ private final static InnterTypeSingletonError app = new InnterTypeSingletonError(); } static InnterTypeSingletonError getInstance(){ System.out.println("APP - 静态内部类方式(Holder)"); return SingletonHolder.app; } public static void main(String[] args){ try { InnterTypeSingletonError.getInstance(); } catch (Throwable t) { t.printStackTrace(); } try { InnterTypeSingletonError.getInstance(); } catch (Throwable t) { t.printStackTrace(); } } } 复制代码
注意看上文中代码块:
private InnterTypeSingletonError(){ System.out.println(5 / 0); } 复制代码
这样一定会出错,运行结果报错信息如下:
APP - 静态内部类方式(Holder) APP - 静态内部类方式(Holder) java.lang.ExceptionInInitializerError at com.design.singleton.InnterTypeSingletonError.getInstance(InnterTypeSingletonError.java:23) at com.design.singleton.InnterTypeSingletonError.main(InnterTypeSingletonError.java:28) Caused by: java.lang.ArithmeticException: / by zero at com.design.singleton.InnterTypeSingletonError.<init>(InnterTypeSingletonError.java:14) at com.design.singleton.InnterTypeSingletonError.<init>(InnterTypeSingletonError.java:11) at com.design.singleton.InnterTypeSingletonError$SingletonHolder.<clinit>(InnterTypeSingletonError.java:18) ... 2 more java.lang.NoClassDefFoundError: Could not initialize class com.design.singleton.InnterTypeSingletonError$SingletonHolder at com.design.singleton.InnterTypeSingletonError.getInstance(InnterTypeSingletonError.java:23) at com.design.singleton.InnterTypeSingletonError.main(InnterTypeSingletonError.java:34) 复制代码复制代码
可以发现它第一次报错是正常的异常,第二次如果再报错就是Could not initialize class ,为什么呢?
因为:「类加载时静态变量只会在第一次加载时,进行初始化,此后不管成不成功,都不会进行第二次初始化了」
所以使用的时候需要注意
枚举方式🧡
public enum EnumSingleton { /*** * APP对象 */ APP; private App app; EnumSingleton() { app = new App(); } public App getInstance() { System.out.println("**************************"); System.out.println("APP - 枚举方式"); return app; } } 复制代码
**评价:**线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用
什么场景适用
在以下情况可以使用单例模式:
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时
Code/生活中的实际应用
在很多项目中的数据库连接池,亦或是配置中心,配置文件对象等等,非常常见~
总结
感谢Java3Y的文章:三歪写Bug写哭了,从中学习到了内部类使用时的神器报错
单例模式使用的场景其实固化,任何需要单一对象工作时的场景都可以使用单例模式,同时只推荐以下三种写法:
基于双重锁校验的懒汉型 静态内部类方式 枚举方式
相关代码链接
GitHub地址
兼顾了《HeadFirst》以及《GOF》两本经典书籍中的案例 提供了友好的阅读指导
break-word; color: #664D9D; font-weight: normal; border-bottom: 1px solid #664D9D;">mdnice 排版
这篇关于【一起学系列】之单例模式:只推荐三种~的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-06小米11i印度快充版ROM合集:极致体验,超越期待
- 2024-10-06【ROM下载】小米11i 5G 印度版系统, 疾速跃迁,定义新速度
- 2024-10-06【ROM下载】小米 11 青春活力版,青春无极限,活力全开
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求