单身模式面试
我最近在接受以下代码的采访时被问及java相关的问题,因为我是java的新手,几乎没有Java代码,所以我真的不知道下面的代码是做什么的。
问题是使用以下代码选择描述最糟糕事情的选项:
public class Bolton { private static Bolton INST = null; public static Bolton getInstance() { if ( INST == null ) { INST = new Bolton(); } return INST; } private Bolton() { } }
以下是此问题的选项
- 可以创建多个Bolton实例
- 永远不会创造博尔顿
- 构造函数是私有的,无法调用
- 可以对值进行垃圾回收,并且对getInstance的调用可能会返回垃圾数据
以上哪个选项是正确的? 为什么?
这是一个单身人士模式
Singleton Pattern的想法是只有一个类的可用实例。 因此, constructor
设置为private
,在这种情况下,类维护一个getInstance()
方法,该方法调用此类中的现有实例变量INST
,或者为执行程序创建一个新实例变量。 答案可能是1,因为它不是线程安全的。 它可能会混淆3,我之前已经放下了,但这是设计,从技术上讲,所以实际上并不是一个缺陷。
以下是来自维基百科的Lazy Initialization ,线程安全单例模式的示例:
public class SingletonDemo { private static volatile SingletonDemo instance = null; private SingletonDemo() { } public static SingletonDemo getInstance() { if (instance == null) { synchronized (SingletonDemo.class){ if (instance == null) { instance = new SingletonDemo(); } } } return instance; } }
将实例变量设置为volatile
告诉Java从内存中读取它并且不将其设置在缓存中。
同步语句或方法有助于并发 。
阅读有关双重检查锁定的更多信息,这是“懒惰初始化”单例的情况
可以创建多个Bolton实例
由于上述代码中缺少同步,此选项是正确的。
假设两个线程同时检查null
并且两者都会发现该值为null
并且两者都将调用构造函数(它反驳单例) 。
此外还有其他捕获,即使两个线程不一起检查null
,但假设一个线程调用构造函数; 但构造函数不会返回,直到构造对象(假设对象创建成本高,需要时间),所以直到构造函数返回一些其他线程可能会检查null
条件并仍然发现对象为null
因为对象不是尚未构建。
这种情况下,一些先决条件被称为check-then-act ,这是Race的罪魁祸首。
对于单身人士,有两种标准正在使用:
- 双重检查锁定
- 基于枚举的单例模式
更新:这是另一篇讨论双重检查锁定的好文章
面试官基本上想检查你的单身人士模式的知识。 模式可以被打破吗? 答案是肯定的。 检查这个或谷歌 – 当单身人士不是单身人士时。
最好的课程是按照Joshua Bloch的建议使用基于Enum的Singleton
应该同步getInstance()
方法,否则如果多个线程同时调用getInstance()
,则可以创建许多实例。 所以我会选择选项1。
当我们想要只有这个类的一个对象时,我们使用Singleton Pattern,它将在每个地方使用。 因此,要限制类创建许多对象,我们应该使用private
作为此类的构造函数。 并创建一个public
函数来返回此类的对象。
public class MethodWin { private int isLoggedOn=0; private static MethodWin objectMethodWin = new MethodWin(); private MethodWin() { } public static MethodWin getInstance() { return objectMethodWin; } public void setIsLoggedOn(int value) { this.isLoggedOn=value; } public int getIsLoggedOn() { return this.isLoggedOn; } }
所以当我们需要创建这个对象时,我们应该:
MethodWin meth = MethodWin.getInstance();
原始答案是只创建了一个Bolton实例。
通过reflection,即使构造函数是私有的,我们也可以创建许多对象。
在multithreading环境中,有可能创建多个实例。
通过序列化,有可能创建多个对象。
简单的答案是2) A Bolton will never be created
因为当你创建实例时,构造函数将在调用getInstance方法时调用内部构造函数初始化,然后回答将创建单个实例。