单例模式面试题及详细答案(真实面试版)_第1页
单例模式面试题及详细答案(真实面试版)_第2页
单例模式面试题及详细答案(真实面试版)_第3页
单例模式面试题及详细答案(真实面试版)_第4页
单例模式面试题及详细答案(真实面试版)_第5页
已阅读5页,还剩1页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

单例模式面试题及详细答案(真实面试版)一、基础概念面试题1.什么是单例模式?核心作用是什么?答案:单例模式是设计模式中创建型模式的一种,核心是保证一个类在整个程序运行过程中,有且仅有一个实例对象,同时提供一个全局访问该实例的入口方法。核心作用:避免类频繁创建、销毁对象,减少内存开销、提升性能保证全局对象唯一性,统一资源访问入口,避免多实例导致的资源冲突方便全局统一管理配置、连接池、工具类等公共资源常见使用场景:数据库连接池、Redis连接工具、全局配置类、日志工具类、系统缓存对象等。2.单例模式的三大核心特点?答案:私有构造方法:禁止外部通过new关键字创建实例私有静态实例对象:类内部持有唯一的实例,禁止外部直接访问公共静态访问方法:对外提供唯一的获取实例的入口3.单例模式分为哪两类?核心区别是什么?答案:分为饿汉式和懒汉式两种:饿汉式:类加载时就直接初始化实例,无论程序是否使用,实例都会创建。线程安全,无延迟加载懒汉式:首次调用获取实例方法时,才初始化对象。延迟加载,节省内存,非原生线程安全二、手写代码面试题(高频必考)1.手写饿汉式单例(最简、推荐日常使用)答案代码:java

//饿汉式单例:类加载即创建实例,线程绝对安全

publicclassSingletonHungry{

//1.私有静态实例,类加载时直接初始化

privatestaticfinalSingletonHungryINSTANCE=newSingletonHungry();

//2.私有构造方法,杜绝外部new

privateSingletonHungry(){}

//3.公共静态方法,全局唯一访问入口

publicstaticSingletonHungrygetInstance(){

returnINSTANCE;

}

}优缺点总结:优点:代码极简、线程绝对安全、无锁、执行效率高。缺点:类加载就初始化,不用也会占用内存,适合实例占用内存小、必用的工具类。2.手写普通懒汉式单例(线程不安全,面试必问坑点)答案代码:java

//普通懒汉式:延迟加载,线程不安全

publicclassSingletonLazy{

//1.声明静态实例,不初始化

privatestaticSingletonLazyinstance;

//2.私有构造

privateSingletonLazy(){}

//3.首次调用才创建实例

publicstaticSingletonLazygetInstance(){

if(instance==null){

instance=newSingletonLazy();

}

returninstance;

}

}坑点解析:多线程环境下,多个线程同时判断instance==null,会同时进入创建对象的代码,最终产生多个实例,破坏单例特性,生产环境绝对不能用。3.手写双重校验锁DCL懒汉式(生产最常用)答案代码:java

//DCL双重校验锁单例:延迟加载、线程安全、高性能

publicclassSingletonDCL{

//1.volatile禁止指令重排,解决空指针隐患

privatestaticvolatileSingletonDCLinstance;

//2.私有构造

privateSingletonDCL(){}

//3.双重校验+锁

publicstaticSingletonDCLgetInstance(){

//第一次校验:避免每次加锁,提升效率

if(instance==null){

//类锁,保证同一时间只有一个线程进入

synchronized(SingletonDCL.class){

//第二次校验:防止多线程等待锁时重复创建

if(instance==null){

instance=newSingletonDCL();

}

}

}

returninstance;

}

}核心重点(面试必问):为什么要两次判空?外层判空避免频繁加锁,提升并发效率;内层判空防止多个线程排队抢锁时重复创建实例。为什么必须加volatile?new对象并非原子操作,会发生指令重排(分配内存→赋值地址→初始化对象),volatile可以禁止重排,避免其他线程获取到未初始化完成的空对象。4.手写静态内部类单例(面试高分写法)答案代码:java

//静态内部类单例:兼顾延迟加载、线程安全、无锁高性能

publicclassSingletonInner{

//私有构造

privateSingletonInner(){}

//静态内部类:仅外部类被调用时才会加载

privatestaticclassInnerInstance{

privatestaticfinalSingletonInnerINSTANCE=newSingletonInner();

}

//全局访问入口

publicstaticSingletonInnergetInstance(){

returnInnerInstance.INSTANCE;

}

}原理&优点:利用JVM类加载机制保证线程安全,静态内部类不会随外部类加载而加载,只有调用getInstance时才会初始化实例,完美实现延迟加载+线程安全+无锁高效,是综合性能最优的写法。5.手写枚举单例(最安全、防反射破解)答案代码:java

//枚举单例:最简单、绝对安全、杜绝破解

publicenumSingletonEnum{

INSTANCE;

//自定义业务方法

publicvoiddoSomething(){

//业务逻辑

}

}核心优势:JDK底层保证枚举天然单例,彻底防止反射、序列化破坏单例,是EffectiveJava推荐的最优单例实现方式。三、进阶高频坑点面试题1.哪些方式可以破坏单例模式?如何解决?答案:常见两种破坏方式及解决方案:反射破坏:通过反射获取私有构造方法,手动new实例。

解决:使用枚举单例,枚举无无参构造,反射无法创建实例;或在私有构造方法中判断实例是否存在,存在则抛出异常。序列化破坏:单例对象序列化后反序列化,会生成新实例。

解决:自定义readResolve()方法,返回原有单例实例;或直接使用枚举单例(枚举序列化天然保证单例)。2.饿汉式为什么线程安全?懒汉式为什么不安全?答案:饿汉式实例在类加载的初始化阶段创建,JVM保证类加载过程是线程互斥的,不会出现多线程并发创建的情况,所以天然线程安全。普通懒汉式是运行时动态创建实例,多线程并发调用getInstance方法时,会出现线程竞争,导致重复创建实例,因此线程不安全。3.DCL单例不加volatile会出现什么问题?答案:new实例的操作会被JVM指令重排,执行顺序可能变为:

1.分配对象内存空间→2.将instance指向内存地址→3.初始化对象。如果线程1执行到第二步、还未初始化对象时,线程2进来判断instance!=null,直接返回未初始化完成的半初始化对象,调用对象方法会出现空指针异常。volatile的作用就是禁止指令重排,保证对象初始化完成后,才会赋值给instance。4.静态内部类单例的延迟加载原理是什么?答案:Java中静态内部类不会跟随外部类的加载而加载,只有当外部类主动调用内部类的静态属性/方法时,才会触发内部类的加载和初始化。因此程序启动加载外部单例类时,不会创建实例,只有调用getInstance方法时,才会加载内部类、初始化唯一实例,天然实现延迟加载,且JVM保证类加载线程安全。5.五种单例写法的适用场景对比?答案:饿汉式:工具类、全局配置类,实例必用、内存占用小普通懒汉式:废弃,并发场景不安全,仅面试考察原理DCL懒汉式:生产最常用,需要延迟加载、高并发场景静态内部类:需要延迟加载、追求极致性能的场景枚举单例:核心业务单例、需要防破解、高安全场景四、面试压轴问答题问:项目中你用的哪种单例?为什么不用其他

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论