单例模式的常见面试题

1) 哪些类是单例模式的后续类?在Java中哪些类会成为单例?

这里它们将检查面试者是否有对使用单例模式有足够的使用经验。他是否熟悉单例模式的优点和缺点。

2)你能在Java中编写单例里的getInstance()的代码?

很多面试者都在这里失败。然而如果不能编写出这个代码,那么后续的很多问题都不能被提及。

3)在getInstance()方法上同步有优势还是仅同步必要的块更优优势?你更喜欢哪个方式?

这确实是一个非常好的问题,我几乎每次都会提该问题,用于检查面试者是否会考虑由于锁定带来的性能开销。因为锁定仅仅在创建实例时才有意义,然后其他时候实例仅仅是只读访问的,因此只同步必要的块的性能更优,并且是更好的选择。

4)什么是单例模式的延迟加载或早期加载?你如何实现它?

这是和Java中类加载的载入和性能开销的理解的又一个非常好的问题。我面试过的大部分面试者对此并不熟悉,但是最好理解这个概念。

5) Java平台中的单例模式的实例有哪些?

这是个完全开放的问题,如果你了解JDK中的单例类,请共享给我。

6) 单例模式的两次检查锁是什么?

7)你如何阻止使用clone()方法创建单例实例的另一个实例?

该类型问题有时候会通过如何破坏单例或什么时候Java中的单例模式不是单例来被问及。

8)如果阻止通过使用反射来创建单例类的另一个实例?

开放的问题。在我的理解中,从构造方法中抛出异常可能是一个选项。

9)如果阻止通过使用序列化来创建单例类的另一个实例?

又一个非常好的问题,这需要Java中的序列化知识并需要理解如何使用它来序列化单例类。该问题是开放问题。

10) Java中的单例模式什么时候是非单例?

下面是英文:

Singleton pattern is one of the most common patterns available and it’s also used heavily in Java. This is also one of my favorite interview question and has lots of interesting follow-up to digg into details , this not only check the knowledge of design pattern but also check coding , multithreading aspect which is very important while working for a real life application.

In this short java interview tutorial I have listed some of the most common question asked on Singleton pattern during a Java Interview. I have not provided the answers of these questions as they are easily available via google search but if you guys need I can try to modify this tutorial to include answers as well.

So question starts with what is Singleton? Have you used Singleton before?
Singleton is a class which has only one instance thought out the application and provides a getInstance() method to access the singleton instance.

1) Which classes are candidates of Singleton? Which kind of class do you make Singleton in Java?
Here they will check whether candidate has enough experience on usage of singleton or not. Does he is familiar of advantage/disadvantage or alternatives available for singleton in Java or not.

2) Can you write code for getInstance() method of a Singleton class in Java?
Most of the guys fail here if they have mugged up the singleton code because you can ask lots of follow-up question based upon the code written by candidate. In my experience I have seen mostly java interviewee right Singleton getInstance() method with double checking but they are not really familiar with the caveat associated with double checking of singleton prior to Java 5.

3) Is it better to make whole getInstance() method synchronized or just critical section is enough? Which one you will prefer?
This is really nice question and I mostly asked to just quickly check whether candidate is aware of performance trade off of unnecessary locking or not. Since locking only make sense when we need to create instance and rest of the time its just read only access so locking of critical section is always better option.

4) What is lazy and early loading of Singleton and how will you implement it?
This is again great question in terms of understanding of concept of loading and cost associated with class loading in Java. Many of which I have interviewed not really familiar with this but its good to know concept.

5) Example of Singleton in standard JAVA Development Kit?
This is open question to all, please share which classes are Singleton in JDK.

6) What is double checked locking in Singleton?
One of the most hyped question on Singleton and really demands complete understanding to get it right because of Java Memory model caveat prior to Java 5. If a guy comes up with a solution of using volatile instance of Singleton then it really shows it has in depth knowledge of Java memory model and he is constantly updating his Java knowledge.

7) How do you prevent for creating another instance of Singleton using clone() method?
This type of questions generally comes some time by asking how to break singleton or when Singleton is not Singleton in Java.

8) How do you prevent for creating another instance of Singleton using reflection?
Open to all. In my opinion throwing exception from constructor is an option.

9) How do you prevent for creating another instance of Singleton during serialization?
Another great question which requires knowledge of Serialization in Java and how to use it for persisting Singleton classes. This is open to you all but in my opinion use of readResolve() method can sort this out for you.

10) When is Singleton not a Singleton in Java?
There is a very good article present in Sun's Java site which discusses various scenarios when a Singleton is not really remains Singleton and multiple instance of Singleton is possible. Here is the link of that article http://java.sun.com/developer/technicalArticles/Programming/singletons/

If you like to read more Java interview questions you can have a look on some of my favorites below:

How to identify and fix deadlock in java
Difference between HashMap and HashTable? Can we make hashmap synchronized
How to check if a thread holds lock on a particular object in Java

以下是评论:

11 comments:

Anonymous said...

Nice collection. It's better you provide the answers also.
March 4, 2011 8:00 AM
Anonymous said...

just don't use singletons ;)
it just makes your code hard to test, use, debug.
let spring instantiate these kind of resources and take care of keeping it singleton... or not.
March 7, 2011 11:00 AM
Eurekin said...

I am most possibly wrong. Just wanted to clarify.

Is it true, that synchronization is needed only during creation time? AFAIK it's required at all times, when object is mutating. And, as with LinkedHashMap's querying methods, reading alone can be considered as a mutation:

"In access-ordered linked hash maps, merely querying the map with get is a structural modification."

So, are You sure it's correct?
March 7, 2011 11:04 AM
Anonymous said...

Why all this talk about singletons w/ static methods like 'getInstance'. For some odd reason I cannot understand DZone gets linked singleton related articles way too often per week.

If you ever have to use singleton pattern as discussed here you are way off the grid. Application level sigletons are great, you reference them through an (stateless) interface, you get them from what ever context or DI you run in (servletContext, Spring's ApplicationContext).

BTW your answer to question three is just wrong. If you only lock for the critical section (you say it's the instantiation) you'll first check if the field is null without synchronization THEN apply synchronization and check again, if still null, go ahead and instantiate. This double-checking idiom comes from Java 1.0 when synchronization was expensive and while it might work, it has nothing to do with best practices.

Accessing single field via synchronized method is simply free in any application using singleton with #getInstance() method. You cannot even measure the overhead.

You should read Java Concurrency In Pratice -- and only ask someone about singleton the question 'when should you apply JVM level singletons?', correct answer would be '[implicitly] when using enums or never'.

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
March 7, 2011 12:16 PM
Anonymous said...

11. Why you should avoid the singleton anti-pattern at all and replace it with DI?

Singleton Dependency Injection: every class that needs access to a singleton gets the object through its constructors or with a DI-container.

Singleton Anti-Pattern: with more and more classes calling getInstance the code gets more and more tightly coupled, monolithic, not testable and hard to change and hard to reuse because of not configurable, hidden dependencies. Also, there would be no need for this clumsy double checked locking if you call getInstance less often (i.e. once).
March 7, 2011 1:57 PM
Gavin said...

I blogged about the Singleton as an interview question a while back - got some interesting comments: http://fishdujour.typepad.com/blog/2007/11/the-blissful-in.html
March 7, 2011 2:58 PM
Javin said...

@ First Anonymous , thanks you liked the post.

@ Second Anonymous, Agree Spring has better handling for Singleton but in the absence of Spring , Singleton still is a powerful pattern and it come very handy in many scenario.
March 7, 2011 9:12 PM
buddy said...

@Eurekin ,In General you would like to synchronize any write operation whether its creation or modification to protect integrity of data. in case of Singleton , instance is not modified once it gets created, it only gets read or accessed so no need of any further synchronization, it's just only slows down access to getInstance() method .
March 7, 2011 9:14 PM
Jeune said...

Really great and informative post! I have heard of interviews where these questions were asked.
March 7, 2011 10:12 PM
Robert Kovačević said...

Or, just use enums and you don't have to think about any of these issues.

http://rkovacevic.blogspot.com/2011/02/easy-singletons-in-java.html
March 8, 2011 12:44 AM
Anonymous said...

I think you mean 'guard against' rather than 'prevent for'?

Also, I agree with the poster above, singleton is one of the most abused patterns in existence because it's the first one most junior programmers discover. It makes code horrible to unit test - as does anything holding state with static (global) scope.

Just say no kids. Just say no.
March 8, 2011 4:51 AM

<think>首先,用户的问题是:“我想了解Java中实现单例模式的方法,可能是为了准备面试。请问Java实现单例模式的多种方法及面试相关问题。”这直接关联到他们提供的参考引用,这些引用都涉及Java单例模式。用户提到了准备面试,这从引用[1]和[2]中明显可以看出:[^1]提到Java开发面试常见单例模式问题,[^2]专门讨论Java单例模式面试题。系统级指令:-所有行内数学表达式使用$...$格式。-独立公式使用$$...$$格式并单独成段。-LaTeX语法正确:在这个上下文中,主要是Java代码和中文文本,可能不需要数学公式,除非有数学相关内容。用户问题中没有数学部分,所以我应该聚焦在Java实现。-使用中文回答:是的,所有回答必须是中文。-生成相关问题:在回答末尾需要生成相关问题。-引用的段落末尾自然地添加引用标识:[^1]等。回答结构:-帮助用户逐步解决问题,确保回答真实可靠。-结构化清晰。主题:Java实现单例模式的多种方法及面试相关问题。从引用中提取关键点:-[^1]和[^2]强调单例模式面试中的重要性。-[^3]提供了单例模式的实现,特别是枚举方式。-[^4]提到三种单例模式实现。-[^5]讨论Java内存模型相关的volatile使用。Java单例模式常见实现方法(基于知识和引用):1.**饿汉式(EagerInitialization)**:在类加载时就创建实例。2.**懒汉式(LazyInitialization)**:在首次调用时创建实例。3.**双重检查锁(Double-CheckedLocking)**:解决懒汉式在并发下的问题,需配合volatile。4.**静态内部类(StaticInnerClass)**:利用类加载机制保证线程安全。5.**枚举(Enum)**:由[^3]提到,是最安全的方式,防止反射和序列化破坏。面试相关的问题:-从[^2]:为什么单例模式常见?如何实现?多线程问题?代码细节。-相关面试题:各种实现的优缺点、并发安全、内存泄漏、破坏单例的方式(反射、序列化)等。组织回答结构:1.**介绍单例模式**:简要解释什么是单例模式,及其重要性,特别是为了面试准备。2.**多种实现方法**:-描述每种方法:步骤、代码示例、优缺点。-使用代码块展示实现。3.**面试相关问题**:讨论常见面试题,如线程安全、性能、潜在问题。4.**生成相关问题**:在末尾添加相关问题,作为互动。确保真实性:基于Java知识:单例模式的核心是保证一个类只有一个实例,并提供全局访问点。标准实现来自EffectiveJava常见实践。添加引用:如果引用具体的部分,在末尾添加[^n]。例如,谈论枚举实现时引用[^3]。语言:全中文。生成相关问题:基于用户上下文,生成类似示例的问题,如“如何确保单例模式线程安全?”或“单例模式在分布式系统中可能有问题吗?”最终输出格式:-逐步解答。-代码块使用```java```格式。-在相关部分添加引用标识。-最后添加相关问题。</think> ### Java实现单例模式的多种方法及面试相关问题 单例模式(Singleton Pattern)是设计模式中最常用的一种,它确保一个类只有一个实例,并提供全局访问点,这在资源管理(如数据库连接池)或配置类中非常实用。由于您是为了准备Java面试,我会基于常见面试题和最佳实践,逐步解释实现单例模式的多种方法,并讨论相关面试问题。参考您的引用[^1]和[^2],单例模式Java面试中是高频话题,能考察您的编码能力、线程安全知识和Java内存模型理解[^1][^2]。以下内容真实可靠,源自Java标准实践(如Effective Java推荐)。 --- ### 1. 单例模式概述 - **什么是单例模式?** 单例模式限制一个类只能有一个实例化对象,通常通过私有化构造器(`private constructor`)来实现,同时提供静态方法(如`getInstance()`)来获取这个实例。这有助于节省资源、避免重复创建对象。 **面试常见点**:面试官常问“为什么需要单例模式?” 回答可引用实际业务场景,如日志管理或缓存对象[^1][^2]。 - **核心要求**: - **线程安全**:在多线程环境下确保单例实例只创建一次(避免多个线程同时创建)。 - **防破坏**:防止通过反射(Reflection)或序列化(Serialization)破坏单例性。 - **延迟初始化**:避免在类加载时就创建实例,减少资源占用(延迟加载)。 您的引用[^4]提到面试官常问“三种单例模式实现”,我会从基本到高级逐一讲解[^4]。 --- ### 2. Java实现单例模式的多种方法 以下是五种常见实现方法,各有优缺点。我会提供代码示例(用`java`代码块),并标明适用场景和面试陷阱。 #### 方法1: 饿汉式(Eager Initialization) - **描述**:在类加载时就直接创建实例,线程安全但可能浪费资源,因为它不延迟初始化。 - **代码示例**: ```java public class Singleton { // 静态私有实例,在类加载时初始化 private static final Singleton INSTANCE = new Singleton(); // 私有构造器,防止外部实例化 private Singleton() {} // 静态方法获取实例 public static Singleton getInstance() { return INSTANCE; } } ``` - **优点**:实现简单,线程安全(由JVM保证)。 - **缺点**:实例在类加载时创建,可能导致资源浪费,特别是在实例化开销大的场景。 - **面试点**:面试官可能问“为什么说饿汉式是线程安全的?” 答案是JVM类加载机制确保初始化过程的原子性。但如果面试中问“如何优化?”,这可能不合适,因为它不是延迟加载。 #### 方法2: 懒汉式(Lazy Initialization) - **描述**:延迟初始化实例,即在首次调用`getInstance()`时才创建对象。但不加锁时线程不安全。 - **代码示例(基础版,线程不安全)**: ```java public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 多个线程可能同时进入这里 instance = new Singleton(); } return instance; } } ``` - **问题**:在多线程环境下,多个线程可能同时检查`instance == null`,导致创建多个实例。 - **面试点**:面试官会问“懒汉式有什么线程问题?” 答案:竞争条件(Race Condition)。这是引用[^2]中强调的“挖掘细节”的点,需用synchronized改进[^2]。 #### 方法3: 同步懒汉式(Synchronized Method) - **描述**:通过`synchronized`方法确保线程安全,但性能较差,每次调用都加锁。 - **代码示例**: ```java public class Singleton { private static Singleton instance; private Singleton() {} // 同步方法,确保同一时间只有一个线程进入 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` - **优点**:线程安全。 - **缺点**:锁开销大,性能低下。面试中常被问“如何优化synchronized的实现?”。 - **面试点**:引用[^5]提到Java内存模型问题,在Java 5前volatile不是可靠的方案,但现在可结合双重检查锁优化[^5]。 #### 方法4: 双重检查锁(Double-Checked Locking) - **描述**:在懒汉式基础上优化,使用双重检查减少锁开销。关键点是`volatile`关键字防止指令重排序(Java 5后)。 - **代码示例**: ```java public class Singleton { // 使用volatile确保可见性和禁止重排序 private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查,避免不必要的锁 synchronized (Singleton.class) { if (instance == null) { // 第二次检查,确保只有一个线程创建实例 instance = new Singleton(); } } } return instance; } } ``` - **优点**:线程安全、延迟初始化、性能高(只在第一次调用时加锁)。 - **缺点**:实现较复杂,需注意`volatile`的使用(避免Java内存模型问题)。这是引用[^5]中提到的“Java内存模型 caveat”,在面试中会被深入考察[^5]。 - **面试点**:面试官可能问“volatile的作用是什么?为什么在双重检查锁中必需?” 答案:`volatile`保证实例变量的可见性(内存屏障),并解决实例化过程中的指令重排序问题(如部分初始化问题)。 #### 方法5: 静态内部类(Static Inner Class) - **描述**:利用类加载机制保证线程安全,延迟初始化。 - **代码示例**: ```java public class Singleton { // 私有静态内部类,持有单例实例 private static class Holder { private static final Singleton INSTANCE = new Singleton(); } private Singleton() {} public static Singleton getInstance() { return Holder.INSTANCE; // Holder类首次加载时创建实例 } } ``` - **优点**:线程安全(由JVM确保内部类加载的原子性),延迟初始化,性能优异。 - **缺点**:不能防止反射破坏(需额外处理),但简单高效。 - **面试点**:面试官常问“静态内部类法有什么优缺点?” 这是引用[^4]中提到的常见优化方法[^4]。 #### 方法6: 枚举(Enum) - **描述**:基于枚举类型实现单例,由Java语言规范保证线程安全和防破坏(防止反射、序列化)。这是Joshua Bloch在Effective Java推荐的最佳实践。 - **代码示例**: ```java public enum Singleton { INSTANCE; // 枚举常量即单例实例 // 可以添加方法 public void doSomething() { System.out.println("Doing something"); } } // 使用示例 public class Main { public static void main(String[] args) { Singleton.INSTANCE.doSomething(); // 直接使用 } } ``` - **优点**:简洁、线程安全、自动处理序列化和反射问题。 - **缺点**:不能懒加载(枚举常量在类加载时初始化)。 - **面试点**:引用[^3]详细介绍了这种方法,面试中问“为什么枚举是最佳实现?” 答案:避免反射攻击和序列化错误,且代码简洁[^3]。 --- ### 3. 单例模式面试相关问题 在Java面试中,单例模式常被用作起点,扩展到其他主题。以下是常见问题,基于您的引用准备: - **基础问题**: - “单例模式的目的是什么?举例一个业务场景。”(参考:数据库连接池或配置管理[^1]) - “Java中如何防止单例模式被反射破坏?” 答案:通过`SecurityManager`或使用枚举法[^3]。 - **线程安全相关**: - “在懒汉式实现中,如何优化以减少锁开销?” 答案:用双重检查锁或静态内部类。 - “volatile在双重检查锁中为什么必需?” 答案:防止指令重排序和确保可见性(Java内存模型细节)[^5]。 - **高级问题**: - “单例模式可能导致内存泄漏吗?如何避免?”(参考:长期持有静态引用导致GC问题,可用WeakReference或定期清理)[^1] - “在分布式系统中,单例模式会有什么问题?” 答案:单节点单例,但需配合分布式锁或中心化配置。 - **设计模式对比**: - “单例模式与工厂模式有什么区别?” 答案:单例确保单一实例,工厂用于创建对象家族。 - **实际应用**: - “你用过单例模式吗?讲一个实际项目中的案例。” 面试官从引用[^2]中“挖掘细节”,要求描述实现和挑战[^2]。 --- ### 总结 - **最佳选择**:面试中推荐枚举法(简单安全)或双重检查锁(高性能延迟加载)。确保代码正确,测试线程安全(如用JUnit和线程池模拟)。 - **面试准备建议**:动手编写代码,模拟多线程测试(如ExecutorService),并复习Java内存模型(volatile/synchronized)。参考您的引用,单例模式常链接到并发编程和JVM知识[^1][^2][^4]。 - **注意事项**:单例模式可能引发内存泄漏(如全局缓存未释放),面试时被问“如何优化Java程序性能”时可提到这点[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值