资讯专栏INFORMATION COLUMN

面试官所认为的单例模式

codeKK / 2554人阅读

摘要:防止指令重排序防止时指令重排序导致其他线程获取到未初始化完的对象。枚举类默认枚举实例的创建是线程安全的,所以不需要担心线程安全的问题。

单例模式是23种GOF模式中最简单,也是最经常出现的一种设计模式,也是面试官最常爱考的一种模式,为什么呢?
因为单例模式足够简单,编写一个单例模式代码几分钟就能搞定,所以设计模式中面试官通常会选取单例模式作为出题。
下面把单例模式分几个点,分别说说哪些地方面试官能考你?

单例模式的意义
通常面试官会很笼统的问你,什么是单例模式?单例模式用来解决了什么痛点?没有单例模式我们会怎么办?单例模式他有什么缺点吗?

单例模式是最简单的设计模式之一,属于创建型模式,它提供了一种创建对象的方式,确保只有单个对象被创建。这个设计模式主要目的是想在整个系统中只能出现类的一个实例,即一个类只有一个对象。
单例模式的解决的痛点就是节约资源,节省时间从两个方面看:

1.由于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级的对象而言,是很重要的.

2.因为不需要频繁创建对象,我们的GC压力也减轻了,而在GC中会有STW(stop the world),从这一方面也节约了GC的时间
单例模式的缺点:简单的单例模式设计开发都比较简单,但是复杂的单例模式需要考虑线程安全等并发问题,引入了部分复杂度。

扩展:从你的回答中能进行哪些扩展呢?我们谈到了GC,有可能这时候就会问你GC,STW等知识。谈缺点的时候谈到了复杂的单例模式,
这个时候可能会问你让你设计一个优秀的单例模式你会怎么设计,会怎么实现?

单例模式的设计
通常这里面试官会问你单例模式怎么设计,需要看重哪些方面?一般来说单例模式有哪些实现方式?

设计单例模式的时候一般需要考虑几种因素:

-线程安全
-延迟加载
-代码安全:如防止序列化攻击,防止反射攻击(防止反射进行私有方法调用)
-性能因素

一般来说,我们去网上百度去搜大概有7,8种实现,,下面列举一下需要重点知道的
饿汉,懒汉(线程安全,线程非安全),双重检查(DCL)(重点),内部类,以及枚举(重点),

扩展:我们上面说到了各个模式的实现,这个时候很有可能会叫你手写各个模式的代码。当然也有可能会问你线程安全,代码安全等知识。

饿汉模式

饿汉模式的代码如下:

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}

饿汉模式代码比较简单,对象在类中被定义为private static,通过getInstance(),通过java的classLoader机制保证了单例对象唯一。
扩展:

有可能会问instance什么时候被初始化?

Singleton类被加载的时候就会被初始化,java虚拟机规范虽然没有强制性约束在什么时候开始类加载过程,但是对于类的初始化,虚拟机规范则严格规定了有且只有四种情况必须立即对类进行初始化,遇到new、getStatic、putStatic或invokeStatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。 生成这4条指令最常见的java代码场景是:1)使用new关键字实例化对象2)读取一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)3)设置一个类的静态字段(被final修饰、已在编译期把结果放在常量池的静态字段除外)4)调用一个类的静态方法

class的生命周期?

class的生命周期一般来说会经历加载、连接、初始化、使用、和卸载五个阶段

class的加载机制

这里可以聊下classloader的双亲委派模型。

双重检查DCL
public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}  

synchronized同步块里面能够保证只创建一个对象。但是通过在synchronized的外面增加一层判断,就可以在对象一经创建以后,不再进入synchronized同步块。这种方案不仅减小了锁的粒度,保证了线程安全,性能方面也得到了大幅提升。

同时这里要注意一定要说volatile,这个很关键,volatile一般用于多线程的可见性,但是这里是用来防止指令重排序的。

扩展:

为什么需要volatile?volatile有什么用?

首先要回答可见性,这个是毋庸质疑的,然后可能又会考到java内存模型。

防止指令重排序: 防止new Singleton时指令重排序导致其他线程获取到未初始化完的对象。instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。1.给 instance 分配内存2.调用 Singleton 的构造函数来初始化成员变量3.将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)

但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后报错。

顺便也可以说下volatie原理用内存屏障

讲讲synchronized和volatile的区别

这里可以从synchroized能保证原子性,volatile不能保证说起,以及讲下synchroized是重量级锁,甚至可以所以下他和Lock的区别等等。

线程安全一般怎么实现的?

互斥同步。如lock,synchroized

非阻塞同步。如cas。

不同步。如threadLocal,局部变量。

枚举类
public enum Singleton{
    INSTANCE;
}

默认枚举实例的创建是线程安全的,所以不需要担心线程安全的问题。同时他也是《Effective Java》中推荐的模式。最后通过枚举类,他能自动避免序列化/反序列化攻击,以及反射攻击(枚举类不能通过反射生成)。

总结

单例模式虽然看起来简单,但是设计的Java基础知识非常多,如static修饰符、synchronized修饰符、volatile修饰符、enum等。这里的每一个知识点都可以变成面试官下手的考点,而单例只是作为一个引子,考到最后看你到底掌握了多少。看你的广度和深度到底是怎么样的。

如果这篇文章对你有帮助,想要了解更多。或者想要1对1的交流。请关注下方公众号吧。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76415.html

相关文章

  • java面试题:java中单例设计模式及两种实现方法的代码举例

    摘要:面试时经常会问到关于单例设计模式,因为它能考察的知识点较多且在开发中经常用到。那我就来说一说我对于单例设计模式的一些浅见。还有另一种实现方法称为懒汉式。但以上代码会出现线程安全问题。 Java面试时经常会问到关于单例设计模式,因为它能考察的知识点较多且在开发中经常用到。那我就来说一说我对于单例设计模式的一些浅见。首先,在Java中,什么是单例呢?就是保证类在内存中只有一个对象。那么问题...

    dadong 评论0 收藏0
  • 又被面试官问设计模式了,我真的是

    摘要:面试官要不你来手写下单例模式呗候选者单例模式一般会有好几种写法候选者饿汉式简单懒汉式在方法声明时加锁双重检验加锁进阶懒汉式静态内部类优雅懒汉式枚举候选者所谓饿汉式指的就是还没被用到,就直接初始化了对象。面试官:我看你的简历写着熟悉常见的设计模式,要不你来简单聊聊你熟悉哪几个吧?候选者:常见的工厂模式、代理模式、模板方法模式、责任链模式、单例模式、包装设计模式、策略模式等都是有所了解的候选者:...

    不知名网友 评论0 收藏0
  • 面试官问我:什么是JavaScript闭包,我该如何回答

    摘要:到底什么是闭包这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。上面这么说闭包是一种特殊的对象。闭包的注意事项通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。从而使用闭包模块化代码,减少全局变量的污染。 闭包,有人说它是一种设计理念,有人说所有的函数都是闭包。到底什么是闭包?这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。这个...

    BenCHou 评论0 收藏0
  • 每日一道面试题(第三期)---一般什么情况下会导致内存泄漏问题

    摘要:显而易见的,当这个是的时,就不存在内存泄漏的问题。这个我在第一期自定义如何有效保证内存泄漏问题已经说得很明白了。 零零碎碎的东西总是记不长久,仅仅学习别人的文章也只是他人咀嚼后留下的残渣。无意中发现了这个每日一道面试题,想了想如果只是简单地去思考,那么不仅会收效甚微,甚至难一点的题目自己可能都懒得去想,坚持不下来。所以不如把每一次的思考、理解以及别人的见解记录下来。不仅加深自己的理解,更要激...

    番茄西红柿 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<