9

我最近在接受以下代码的采访时被问到与 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 可能会返回垃圾数据

以上哪个选项是正确的?为什么?

4

8 回答 8

8

这是一个单例模式

单例模式的想法是只有一个类的可用实例。因此,在这种情况下,constructor将 设置为private并且类维护一个getInstance()方法,该方法要么调用此类中的现有实例变量,要么INST为正在执行的程序创建一个新实例变量。答案可能是 1,因为它不是线程安全的。它可能对我之前放下的 3 感到困惑,但从技术上讲,这是设计使然,因此实际上并不是缺陷。

这是来自维基百科的惰性初始化,线程安全的单例模式的示例:

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 从内存中读取它而不将其设置在缓存中。

同步的语句或方法有助于并发

阅读有关双重检查锁定的更多信息,这是“延迟初始化”单例发生的情况

于 2013-03-15T05:25:02.817 回答
2

面试官主要是想检查你对单例模式的了解。模式可以打破吗?答案是肯定的。检查这个或谷歌 - 当单例不是单例时。

最好的课程是使用Joshua Bloch 建议的基于枚举的 Singleton

于 2013-03-15T05:24:43.520 回答
2

可以创建多个 Bolton 实例

由于上述代码中缺乏同步,此选项是正确的。

假设两个线程同时检查null并且都将发现值是null并且都将调用构造函数(这反驳了单例)

这还有其他问题,即使两个线程不null一起检查但假设一个线程调用构造函数;但是在构造对象之前构造函数不会返回(假设创建对象的成本很高并且需要时间),所以在构造函数返回之前,其他线程可能会检查null条件并仍然找到对象,null因为对象尚未构造.

在这种情况下,某些先决条件被称为check-then-act,这是 Race 的罪魁祸首。

对于单例,有两个正在使用的标准:

更新: 这是另一篇很棒的文章,讨论了双重检查锁定

于 2013-03-15T05:34:18.403 回答
1

getInstance()方法应该是同步的,否则如果多个线程getInstance()同时调用,可能会创建许多实例。所以我会选择选项1。

于 2013-03-15T05:28:27.347 回答
1

当我们只想拥有这个类的一个对象并且它将在任何地方使用时,我们会使用单例模式。所以为了限制类创建多个对象,我们应该使用 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();
于 2013-03-15T06:09:10.443 回答
0

原始答案是只创建了一个 Bolton 实例。

于 2013-03-15T05:48:21.913 回答
0

通过反射我们可以创建许多对象,即使构造函数是私有的。
在多线程环境中,有机会创建多个实例。
通过序列化有机会创建多个对象。

于 2013-03-15T05:52:04.330 回答
0

简单的答案是2) A Bolton will never be created因为当您创建实例时,构造函数将在调用 getInstance 方法时调用内部构造函数初始化,然后答案将是创建单个实例。

于 2013-03-15T05:57:56.947 回答