首页
题库
公司真题
专项练习
面试题库
在线编程
面试
面试经验
AI 模拟面试
简历
求职
学习
基础学习课
实战项目课
求职辅导课
专栏&文章
竞赛
我要招人
发布职位
发布职位、邀约牛人
更多企业解决方案
AI面试、笔试、校招、雇品
HR免费试用AI面试
最新面试提效必备
登录
/
注册
Kitebin
深圳大学 C++
发布于广东
关注
已关注
取消关注
@猿兄:
轻松手写单例模式的6种实现方式!再也不怕面试官问了!
之前分享:高频Java基础面试题高频Java集合面试题 今天分享一些面试高频的单列模式的6种实现方式。 整理分享不易,先点赞评论收藏支持一波再看鸭~ 文章目录: 一、单例模式的定义 定义: 确保一个类只有一个实例,并提供该实例的全局访问点。 这样做的好处是:有些实例,全局只需要一个就够了,使用单例模式就可以避免一个全局使用的类,频繁的创建与销毁,耗费系统资源。 二、单例模式的设计要素 一个私有构造函数 (确保只能单例类自己创建实例) 一个私有静态变量 (确保只有一个实例) 一个公有静态函数 (给使用者提供调用方法) 简单来说就是,单例类的构造方法不让其他人修改和使用;并且单例类自己只创建一个实例,这个实例,其他人也无法修改和直接使用;然后单例类提供一个调用方法,想用这个实例,只能调用。这样就确保了全局只创建了一次实例。 三、单例模式的6种实现及各实现的优缺点 (一)懒汉式(线程不安全) 实现: public class Singleton { private static Singleton uniqueInstance; private Singleton() { } public static Singleton getUniqueInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; }} 说明: 先不创建实例,当第一次被调用时,再创建实例,所以被称为懒汉式。 优点: 延迟了实例化,如果不需要使用该类,就不会被实例化,节约了系统资源。 缺点: 线程不安全,多线程环境下,如果多个线程同时进入了 if (uniqueInstance == null) ,若此时还未实例化,也就是uniqueInstance == null,那么就会有多个线程执行 uniqueInstance = new Singleton(); ,就会实例化多个实例; (二)饿汉式(线程安全) 实现: public class Singleton { private static Singleton uniqueInstance = new Singleton(); private Singleton() { } public static Singleton getUniqueInstance() { return uniqueInstance; }} 说明: 先不管需不需要使用这个实例,直接先实例化好实例 (饿死鬼一样,所以称为饿汉式),然后当需要使用的时候,直接调方法就可以使用了。 优点: 提前实例化好了一个实例,避免了线程不安全问题的出现。 缺点: 直接实例化好了实例,不再延迟实例化;若系统没有使用这个实例,或者系统运行很久之后才需要使用这个实例,都会操作系统的资源浪费。 (三)懒汉式(线程安全) 实现: public class Singleton { private static Singleton uniqueInstance; private static singleton() { } private static synchronized Singleton getUinqueInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; }} 说明: 实现和 线程不安全的懒汉式 几乎一样,唯一不同的点是,在get方法上 加了一把 锁。如此一来,多个线程访问,每次只有拿到锁的的线程能够进入该方法,避免了多线程不安全问题的出现。 优点: 延迟实例化,节约了资源,并且是线程安全的。 缺点: 虽然解决了线程安全问题,但是性能降低了。因为,即使实例已经实例化了,既后续不会再出现线程安全问题了,但是锁还在,每次还是只能拿到锁的线程进入该方***使线程阻塞,等待时间过长。 (四)双重检查锁实现(线程安全) 实现: public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() { } public static Singleton getUniqueInstance() { if (uniqueInstance == null) { synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } } 说明: 双重检查数相当于是改进了 线程安全的懒汉式。线程安全的懒汉式 的缺点是性能降低了,造成的原因是因为即使实例已经实例化,依然每次都会有锁。而现在,我们将锁的位置变了,并且多加了一个检查。 也就是,先判断实例是否已经存在,若已经存在了,则不会执行判断方法内的有锁方法了。 而如果,还没有实例化的时候,多个线程进去了,也没有事,因为里面的方法有锁,只会让一个线程进入最内层方法并实例化实例。如此一来,最多最多,也就是第一次实例化的时候,会有线程阻塞的情况,后续便不会再有线程阻塞的问题。 为什么使用 volatile 关键字修饰了 uniqueInstance 实例变量 ? uniqueInstance = new Singleton(); 这段代码执行时分为三步: 为 uniqueInstance 分配内存空间 初始化 uniqueInstance 将 uniqueInstance 指向分配的内存地址 正常的执行顺序当然是 1>2>3 ,但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。单线程环境时,指令重排并没有什么问题;多线程环境时,会导致有些线程可能会获取到还没初始化的实例。例如:线程A 只执行了 1 和 3 ,此时线程B来调用 getUniqueInstance(),发现 uniqueInstance 不为空,便获取 uniqueInstance 实例,但是其实此时的 uniqueInstance 还没有初始化。 解决办法就是加一个 volatile 关键字修饰 uniqueInstance ,volatile 会禁止 JVM 的指令重排,就可以保证多线程环境下的安全运行。 优点: 延迟实例化,节约了资源;线程安全;并且相对于 线程安全的懒汉式,性能提高了。 缺点: volatile 关键字,对性能也有一些影响。 (五)静态内部类实现(线程安全) 实现: public class Singleton { private Singleton() { } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getUniqueInstance() { return SingletonHolder.INSTANCE; }} 说明: 首先,当外部类 Singleton 被加载时,静态内部类 SingletonHolder 并没有被加载进内存。当调用 getUniqueInstance() 方法时,会运行 return SingletonHolder.INSTANCE; ,触发了 SingletonHolder.INSTANCE ,此时静态内部类 SingletonHolder 才会被加载进内存,并且初始化 INSTANCE 实例,而且 JVM 会确保 INSTANCE 只被实例化一次。 优点: 延迟实例化,节约了资源;且线程安全;性能也提高了。 (六)枚举类实现(线程安全) 实现: public enum Singleton { INSTANCE; //添加自己需要的操作 public void doSomeThing() { }} 说明: 默认枚举实例的创建就是线程安全的,且在任何情况下都是单例。 优点: 写法简单,线程安全,天然防止反射和反序列化调用。 防止反序列化序列化:把java对象转换为字节序列的过程;反序列化: 通过这些字节序列在内存中新建java对象的过程;说明: 反序列化 将一个单例实例对象写到磁盘再读回来,从而获得了一个新的实例。我们要防止反序列化,避免得到多个实例。枚举类天然防止反序列化。其他单例模式 可以通过 重写 readResolve() 方法,从而防止反序列化,使实例唯一重写 readResolve() : private Object readResolve() throws ObjectStreamException{ return singleton;} 四、单例模式的应用场景 应用场景举例: 网站计数器。 应用程序的日志应用。 Web项目中的配置对象的读取。 数据库连接池。 多线程池。 ...... 使用场景总结: 频繁实例化然后又销毁的对象,使用单例模式可以提高性能。 经常使用的对象,但实例化时耗费时间或者资源多,如数据库连接池,使用单例模式,可以提高性能,降低资源损坏。 使用线程池之类的控制资源时,使用单例模式,可以方便资源之间的通信。 以上就是单例模式的6中实现方式了,好好理解一下,下次面试问这个就一点不虚了! 看完之后,如果还有什么不懂的,可以在评论区留言,会及时回答更新。 最后,记得点赞评论收藏支持一波鸭~
点赞 11
评论 3
全部评论
推荐
最新
楼层
暂无评论,快来抢首评~
相关推荐
07-17 15:11
桂林电子科技大学 Java
提前批大家投了吗?投哪家了?
感觉牛客里没什么人发啊,是大家都没投嘛?还是投了还没进度呢?
给点吧求求了:
实习还没啥产出呢,再憋两月再投
点赞
评论
收藏
分享
07-18 18:20
北京交通大学 前端开发其它
应届生入职一周,离职的心越来越强烈了
周一入职,在无所事事焦虑中度过了三天。第四天迎来了任务,那么问题来了,我真的一点不会,且一点也没听懂,连问都不知道怎么问,也没有培训,没有人带。自己摸索新软件,仍是云里雾里。终于体会到入职就想离职,心已死。只能祈祷下周一定要学会,不然真的不知道怎么办了
职场新人体验
点赞
评论
收藏
分享
07-03 15:03
复旦大学 算法工程师
这是什么层级的耐面王
我真是 从本科一直面到研究生愣是一次字节也没去
Bolee:
一般般吧,看看我的
查看图片
点赞
评论
收藏
分享
07-01 23:23
郑州大学 Java
大一小登勇闯开源之夏
否极泰来来来来:
牛客迟早有高三的
点赞
评论
收藏
分享
07-17 14:01
安徽新华学院 产品经理
我真是服了,怎么工作了还有人抄作业啊
昨天mentor同时给我和另一个实习一样的工作,让我俩各自做一部分,今天交刚才mentor催我俩发给他,同组实习生竟然直接跟我说:做完了吗?做完了借我抄一下我??
程序员小白条:
学生思维
实习生的蛐蛐区
点赞
评论
收藏
分享
评论
点赞成功,聊一聊 >
点赞
收藏
分享
评论
提到的真题
返回内容
全站热榜
更多
1
...
百度提前批一面
2.6W
2
...
回忆录:后端鼠鼠苦苦哀求日常实习
9075
3
...
去一座新的城市,开始一段新的旅途
3940
4
...
大三双非水产专业上岸阿里后端(一)
3565
5
...
焦虑麻了
2621
6
...
天塌了,自制力差,学了一学期的JavaSE,暑假玩了四五天天,花了八九天把笔记都看了了一遍发现记不住,就花了九天去学MySQL,然后再回过来练习Javase面试,随机抽了两个题目,线程的生命周期,Ar
2531
7
...
一线城市生存成本分析:月薪多少才够用?
2516
8
...
做题家,内卷魔怔人是如何破坏大环境的?
2321
9
...
实习转正,看的不只是硬实力
2079
10
...
26届何去何从
1960
创作者周榜
更多
正在热议
更多
#
风评不好的公司,你会去吗?
#
37587次浏览
230人参与
#
假如你的老板掉河里,你的工作能为他做什么
#
31257次浏览
380人参与
#
第一份工作应该选高薪还是热爱?
#
72276次浏览
699人参与
#
职场新人体验
#
4130次浏览
55人参与
#
你觉得第一学历对求职有影响吗?
#
95737次浏览
675人参与
#
外包能不能当跳板?
#
38018次浏览
228人参与
#
你觉得早上几点上班合适?
#
73750次浏览
308人参与
#
学历贬值真的很严重吗?
#
26550次浏览
180人参与
#
推荐一首陪你工作的歌吧
#
15333次浏览
99人参与
#
秋招签约后的心态变化
#
84155次浏览
821人参与
#
双非能在秋招上岸吗?
#
223416次浏览
1180人参与
#
听劝,这个公司值得去吗
#
487846次浏览
1709人参与
#
不考虑薪资和职业,你最想做什么工作呢?
#
93526次浏览
692人参与
#
打工人的工作餐日常
#
55069次浏览
436人参与
#
反问环节如何提问
#
93850次浏览
1938人参与
#
大学最后一个寒假,我想……
#
47462次浏览
576人参与
#
面试被问第一学历差时该怎么回答
#
138039次浏览
853人参与
#
一人推荐一个值得去的通信/硬件公司
#
187231次浏览
1861人参与
#
月薪多少能在一线城市生存
#
37434次浏览
357人参与
#
机械制造秋招总结
#
54707次浏览
513人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务