Java 单亲模式访谈

Java 单亲模式访谈,java,singleton,Java,Singleton,我最近在接受以下代码采访时被问及与java相关的问题,因为我对java非常陌生,几乎不使用java编写代码,所以我真的不知道下面的代码做什么 问题是 选择用以下代码描述最糟糕情况的选项: public class Bolton { private static Bolton INST = null; public static Bolton getInstance() { if ( INST == null ) {

我最近在接受以下代码采访时被问及与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不是singleton时

    最好的方法是按照Joshua Bloch的建议使用这是一个

    单例模式的思想是一个类只有一个可用实例。因此,
    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;
        }
    
    }
    
    将实例变量设置为告诉Java从内存中读取它,而不是在缓存中设置它

    帮帮忙

    阅读更多关于“惰性初始化”单例会发生什么的信息应该同步
    getInstance()
    方法,否则如果多个线程同时调用
    getInstance()
    ,可能会创建多个实例。所以我会选择选项1

    可以创建多个Bolton实例

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

    假设两个线程同时检查
    null
    ,两个线程都会发现值是
    null
    ,并且都会调用构造函数(它会拒绝singleton)

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

    在这种情况下,一些先决条件被称为检查然后行动,这是种族的罪魁祸首

    对于singleton,有两种标准正在使用:

    更新:
    这是另一篇伟大的文章,它讨论了原始答案是只创建了一个博尔顿实例

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

    简单的答案是
    2)永远不会创建Bolton
    ,因为当您创建实例时,构造函数将在构造函数初始化内部调用调用getInstance方法,然后答案将是创建单个实例

    当我们只想拥有这个类的一个对象时,我们使用单例模式,它将在任何地方使用。因此,为了限制该类创建许多对象,我们应该对该类的构造函数使用
    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();
    

    我会和1一起去。基本上,没有线程同步。这将允许两个或多个线程创建该类的多个实例。我还建议它打破Java命名惯例,但这不是一个选项。从技术上讲,2也是正确的。仅从这段代码中,将永远不会创建
    Bolton
    (实际上不会调用getInstance()。:)@杰克·斯托弗勒:我喜欢你的思维方式,我将把这一点添加到我们的面试问题中;)好吧,我站在更正,同步问题实际上没有发生在我身上。。。是时候重写我的单身汉了@Thihara欢迎来到我的世界:谢谢你的详细回答。有人问我时,我选择了3。正如我所提到的,这是一个疯狂的猜测,我对Java知之甚少(.但这对我将来会有帮助,否则我可能会开始用Java弄脏我的手。:)选择2怎么样?基于@JakeStoeffler注释。将创建一个
    Bolton
    ,但仅作为实例变量。我认为他指的是没有创建调用它的
    main()
    方法的事实。-1对于@Christopher来说,你的代码中似乎有一个输入错误-你错误地将
    getInstance
    方法包含在构造函数体中实际上Bloch说双重检查是一种选择的技术,但是变量必须声明为
    volatile
    (因为如果实例已经初始化,则没有锁)。当然,一旦您修复了该变量,我将恢复为+1:),您的答案非常全面。@Javier我已经编辑过了。我的错。我还读到,即使我们进行双重锁定,也不安全。对于该枚举,应使用模式。