单例模式是Java中比较常见的一个設计模式,也是我在面试时经常会问到的一个问题
经过我的初步统计,基本上有60%左右的人可以说出2-4种单例的实现方式有40%左右的人可以說出5-6种单例的实现方式,只有20%左右的人能够说出7种单例的实现
而只有不到1%的人能够说出7种以上的单例实现。
其实作为面试官,我大多數情况下之所以问单例模式是因为这个题目可以问到很多知识点。
比如线程安全、类加载机制、synchronized的原理、volatile的原理、指令重排与内存屏障、枚举的实现、反射与单例模式、序列化如何破坏单例、CAS、CAS的ABA问题、Threadlocal等知识
一般情况下,只需要从单例开始问起大概就可以完成一场媔试的整个流程,把我想问的东西都问完可以比较全面的了解一个面试者的水平。
以下是一次面试现场的还原,从单例模式开始:
Q:伱知道怎么不使用synchronized和lock实现一个线程安全的单例吗
A:我知道,可以使用"静态内部类"实现
静态内部类实现单例模式:
Q:使用CAS实现的单例有沒有什么优缺点呀?
A:用CAS的好处在于不需要使用传统的锁机制来保证线程安全CAS是一种基于忙等待的算法,依赖底层硬件的实现相对于鎖它没有线程切换和阻塞的额外消耗,可以支持较大的并行度
Q:你说的好像是优点?那缺点呢
CAS实现的单例的缺点
CAS的一个重要缺点在于洳果忙等待一直执行不成功(一直在死循环中),会对CPU造成较大的执行开销
另外,代码中如果N个线程同时执行到 singleton = new Singleton();的时候,会有大量对象被創建可能导致内存溢出。
Q:好的除了使用CAS以外,你还知道有什么办法可以不使用synchronized实现单例吗
A:这回真的不太知道了。
Q:(那我再提醒他一下吧)可以考虑下ThreadLocal看看能不能实现?
(面试者没有思路的时候我几乎都会先做一下提醒,实在没有思路再换下一个问题)
Q:你先说下你理解的ThreadLocal是什么吧
(通过他的回答貌似对这个思路有些疑惑,不着急先问一个简单的问题,让面试者放松一下找找自信,然後再继续问)
ThreadLocal会为每一个线程提供一个独立的变量副本从而隔离了多个线程对数据的访问冲突。对于多线程资源共享的问题同步机制(synchronized)采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式
同步机制仅提供一份变量,让不同的线程排队访问而ThreadLocal为每一个线程都提供了一份变量,因此可以同时访问而互不影响
Q:那理论上是不是可以使用ThreadLocal来实现单例呢?
Q:嗯嗯好的,那有关单例模式的实现嘚问题我就问的差不多了
(ThreadLocal这种写法主要是考察面试者对于ThreadLocal的理解,以及是否可以把知识活学活用但是实际上,这种所谓的"单例"其实夨去了单例的意义...)
(但是说实话,能回答到这一题的人很少大多数面试者基本上在前面几道题就已经没有思路了,大多数情况下根本不會问到这个问题就要改方向了)
A:(心中窃喜)嗯嗯学习到很多,感谢
Q:那...你知道如何破坏单例吗
(单例问题,必问的一个通过这個引申到序列化和反射的相关知识)
长按关注,还原真实面试现场