单身模式面试

我最近在接受以下代码的采访时被问及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() { } } 

以下是此问题的选项

  1. 可以创建多个Bolton实例
  2. 永远不会创造博尔顿
  3. 构造函数是私有的,无法调用
  4. 可以对值进行垃圾回收,并且对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方法时调用内部构造函数初始化,然后回答将创建单个实例。