首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

快速理解设计模式:单例模式深入

  • 25-03-02 11:43
  • 2342
  • 10666
blog.csdn.net

目录

一、单例模式的定义和应用场景

(一)定义及基本要点

(二)应用场景

二、饿汉式单例模式

(一)基本代码展示分析

(二)基本分析和建议

三、懒汉式单例模式(双重检查锁)

(一)基本代码展示分析

(二)基本分析和建议

四、静态内部类实现单例模式

(一)基本代码展示分析

(二)基本分析和建议

五、注册式单例模式

(一)枚举式单例模式代码及分析:(Effective Java推荐单例模式)

(二)容器式单例模式代码及分析:(适用于实例非常多的情况,便于管理,但是是非线程安全的)

参考书籍、文献和资料


干货分享,感谢您的阅读!

一、单例模式的定义和应用场景

(一)定义及基本要点

单例模式是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

该模式有三个基本要点:

  • 一是这个类只能有一个实例;
  • 二是它必须自行创建这个实例;
  • 三是它必须自行向整个系统提供这个实例。

(二)应用场景

应用场景:J2EE中的ServlertContext、SerletContextConfig等、Spring框架应用中的ApplicationContext、数据库连接池等。

二、饿汉式单例模式

(一)基本代码展示分析

  1. /**
  2. * 描述:饿汉式单例模式
  3. * 优点:没有任何锁,执行效率高,用户体验比懒汉式单例模式更好
  4. * 缺点:类加载的时候就初始化,不管用不用都占内存空间
  5. * 建议:适用于单例模式较少的场景
  6. * 如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
  7. * 如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。
  8. *
  9. * @author yanfengzhang
  10. * @date 2020-01-02 20:39
  11. */
  12. public class HungrySingleton {
  13. private final static HungrySingleton HUNGRY_SINGLETON = new HungrySingleton();
  14. private HungrySingleton() {
  15. }
  16. public static HungrySingleton getInstance() {
  17. return HUNGRY_SINGLETON;
  18. }
  19. }

(二)基本分析和建议

优点:没有任何锁,执行效率高,用户体验比懒汉式单例模式更好
缺点:类加载的时候就初始化,不管用不用都占内存空间
建议:

  • 适用于单例模式较少的场景
  • 如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
  • 如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。

三、懒汉式单例模式(双重检查锁)

(一)基本代码展示分析

  1. /**
  2. * 描述:懒汉式单例模式---双重检查锁
  3. * 相比单锁而言,双重检查锁性能上虽然有提升,但是依旧用到了synchronized关键字总归要上锁,对程序性能还是存在一定的性能影响
  4. * 不算最优--存在优化空间
  5. *
  6. * 建议:如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
  7. * 如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。
  8. *
  9. * @author yanfengzhang
  10. * @date 2020-01-02 20:53
  11. */
  12. public class LazyDoubleCheckSingleton {
  13. /**
  14. * volatile 关键字可以保证线程间变量的可见性,还有一个作用就是阻止局部重排序的发生
  15. */
  16. private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
  17. private LazyDoubleCheckSingleton() {
  18. }
  19. public static LazyDoubleCheckSingleton getInstance() {
  20. if (null == lazyDoubleCheckSingleton) {
  21. synchronized (LazyDoubleCheckSingleton.class) {
  22. if (null == lazyDoubleCheckSingleton) {
  23. lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
  24. }
  25. }
  26. }
  27. return lazyDoubleCheckSingleton;
  28. }
  29. }

(二)基本分析和建议

相比单锁而言,双重检查锁性能上虽然有提升,但是依旧用到了synchronized关键字总归要上锁,对程序性能还是存在一定的性能影响。注意里面volatile的使用!!!

建议:

  • 如果我们在程序启动后,一定会加载到类,那么用饿汉模式实现的单例简单又实用;
  • 如果我们是写一些工具类,则优先考虑使用懒汉模式,可以避免提前被加载到内存中,占用系统资源。

四、静态内部类实现单例模式

(一)基本代码展示分析

  1. /**
  2. * 描述:屏蔽饿汉式单例模式的内存浪费问题和双重检查锁中synchronized的性能问题
  3. * 避免因为反射破坏单例
  4. *
  5. * @author yanfengzhang
  6. * @date 2020-01-02 21:08
  7. */
  8. public class LazyInnerClassSingleton {
  9. /**
  10. * 使用LazyInnerClassSingleton的时候会先默认初始化换内部类
  11. * 如果没有使用,则内部类是不加载的
  12. */
  13. private LazyInnerClassSingleton() {
  14. /*为了避免反射破坏单例,需要在构造方法中增加限制,一旦出现多次重复创建,直接抛出异常*/
  15. if (null != Lazyholder.LAZY_INNER_CLASS_SINGLETON) {
  16. throw new RuntimeException("创建LazyInnerClassSingleton异常,不允许创建多个实例!");
  17. }
  18. }
  19. /**
  20. * 每一个关键字都不是多余的,static是为了使单例的空间共享,保证这个方法不会被重写、重载
  21. */
  22. public static final LazyInnerClassSingleton getInstance() {
  23. /*在返回结果前,一定会先加载内部类*/
  24. return Lazyholder.LAZY_INNER_CLASS_SINGLETON;
  25. }
  26. /**
  27. * 默认不加载
  28. */
  29. private static class Lazyholder {
  30. private static final LazyInnerClassSingleton LAZY_INNER_CLASS_SINGLETON = new LazyInnerClassSingleton();
  31. }
  32. }

(二)基本分析和建议

屏蔽饿汉式单例模式的内存浪费问题和双重检查锁中synchronized的性能问题,同时考虑避免因为反射破坏单例问题。

相对而言性能最好!

五、注册式单例模式

注册式单例模式/登记式单例模式,将每个实例都登记到一个地方,使用唯一的标识获取单例。

注册单例模式有两种:枚举式单例模式+容器式单例模式

(一)枚举式单例模式代码及分析:(Effective Java推荐单例模式)

  1. /**
  2. * 描述:注册式单例模式/登记式单例模式,将每个实例都登记到一个地方,使用唯一的标识获取单例。
  3. * 注册单例模式有两种:枚举式单例模式+容器式单例模式
  4. * 此为枚举式单例模式---Effective Java推荐单例模式
  5. *
  6. * @author yanfengzhang
  7. * @date 2020-01-03 09:59
  8. */
  9. public enum EnumSingleton {
  10. /*枚举式单例模式*/
  11. INSTANCE;
  12. private Object data;
  13. public Object getData() {
  14. return data;
  15. }
  16. public void setData(Object data) {
  17. this.data = data;
  18. }
  19. public static EnumSingleton getInstance() {
  20. return INSTANCE;
  21. }
  22. }

(二)容器式单例模式代码及分析:(适用于实例非常多的情况,便于管理,但是是非线程安全的)

  1. /**
  2. * 描述:注册式单例模式/登记式单例模式,将每个实例都登记到一个地方,使用唯一的标识获取单例。
  3. * 注册单例模式有两种:枚举式单例模式+容器式单例模式
  4. * 建议:容器式单例模式适用于实例非常多的情况,便于管理,但是是非线程安全的。
  5. *
  6. * @author yanfengzhang
  7. * @date 2020-01-03 10:51
  8. */
  9. public class ContainerSingleton {
  10. private ContainerSingleton() {
  11. }
  12. private static Map ioc = new ConcurrentHashMap<>();
  13. public static Object getBean(String className) {
  14. synchronized (ioc) {
  15. if (ioc.containsKey(className)) {
  16. return ioc.get(className);
  17. }
  18. Object obj = null;
  19. try {
  20. obj = Class.forName(className).newInstance();
  21. ioc.put(className, obj);
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. return obj;
  26. }
  27. }
  28. }

参考书籍、文献和资料

1.《Sring 5 核心原理与30个类手写实战》,谭勇徳,中国公信出版社,2019.

2.极客时间课程《Java性能调优实战》,刘超,2019.

注:本文转载自blog.csdn.net的张彦峰ZYF的文章"https://zyfcodes.blog.csdn.net/article/details/105652399"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top