单例模式及其使用场景

单例模式(Singleton):指在一个系统中某个类只存在一个实例,类中自行实例化,实例向该系统提供统一的访问接口。

单例模式有两种表现形式,饿汉式:类加载时,就进行实例化;懒汉式,第一次引用类时才进行实例化。

饿汉式,代码如图1所示,我们以日志记录器类为例进行说明。

在类加载时,logger会被初始化。图1中第6行代码私有了构造方法,保证不被外部代码直接实例化。由于构造函数私有,该类无法被继承。通过getInstance方法获得实例,实例再通过info方法统一操作日志文件。

懒汉式

图2中9---11行,在多个线程同时在这一区块(临界区)执行时,由于线程的走走停停特性,可能会得到多个实例。例如线程一刚好执行完图2第9行代码,此时由于分配给线程一的时间片用完,轮到线程二执行图2中第9行代码后,假如又执行了第10行代码,而后线程一得到了时间片可以继续执行第10行代码,这时就会存在两个logger对象。

解决方式一,如图3,可以解决多线程问题,然而所有线程会排队等锁,这就意味着每次调用getInstance方法时都需要获取锁才会执行,这对调用方可能有影响。


解决方式二,如图4第4行,静态变量logger被volatile修饰,能保证各个线程中访问logger时的一致性,即如果线程一修改了logger的值,其它线程在访问logger变量的值时会得到修改后的值。但是如果不加图4中第10---11、13---14行代码,也同样会面临图2中遇到的问题,会创建多个logger实例。因此,当多个线程在执行图4中10---14行代码是,只有第一个线程可以进入,创建完实例后离开,而后在排队等待锁的第二个线程获得锁进入10---14行代码块,此时因为volatile关键字的作用,线程二访问到的logger变量已经不为空,因11,13行代码对logger进行了判断,就不会再创建新的实例。在排队等待锁的第三、四、...等线程情况与第二线程类似,此时,如果再有线程进入getInstance方法,图4中的第9、15行将会判断logger是否为空,如果不为空就不会去排队等待进入10---14行代码的锁,这样,后面的线程在执行gelInstance方法时的速度就会得到提高,而不会引起调用方阻塞。

使用场景:唯一序列;只能允许一个线程访问(如计数器,确保线程安全);创建一个对象需要消耗的资源多(如写日志)等。

相关推荐
某空_10 分钟前
【Android】线程池解析
java
q***116519 分钟前
总结:Spring Boot 之spring.factories
java·spring boot·spring
追风少年浪子彦33 分钟前
Spring Boot 使用自定义 JsonDeserializer 同时支持多种日期格式
java·spring boot·后端
牢七43 分钟前
Javan
java
我叫黑大帅1 小时前
六边形架构?小白也能秒懂的「抗造代码秘诀」
java·后端·架构
不穿格子的程序员1 小时前
Java基础篇——JDK新特性总结
java·虚拟线程·jdk新特性
一乐小哥1 小时前
Java8 党狂喜!这篇把 Java9 到 25 的实用新功能讲透了,新手也能直接抄
java
草莓熊Lotso1 小时前
Git 本地操作进阶:版本回退、撤销修改与文件删除全攻略
java·javascript·c++·人工智能·git·python·网络协议
Ka1Yan1 小时前
[数组] - LeetCode 704. 二分查找
java·开发语言·算法·leetcode·职场和发展
合作小小程序员小小店1 小时前
web网页开发,在线%餐饮点餐%系统,基于Idea,html,css,jQuery,java,ssm,mysql。
java·前端·数据库·html·intellij-idea·springboot