java - 单例类设计——空对象

标签 java multithreading singleton class-design

我和一位同事正在辩论:

我们有一个在我们代码库的多个地方使用的单例类。

最初,类的设计方式是您可以获得类对象,但该对象不会被完全初始化。

我的意思是:

mySingleton.getInstance().SomeMethod();

SomeMethod 会导致错误,因为该类未初始化。为了使类(class)正常工作,必须这样做:

mySingleton.getInstance().initObject();

mySingleton.getInstance().SomeMethod();

无论如何,我的争论是构造函数(用第一个 get 实例调用)应该调用 initObject 以便不会抛出任何错误。

你怎么看?

我的同事喜欢另一种方式,所以他知道类何时初始化。 (即他在 1 个特定的代码行调用 initObject 并希望没有其他东西首先需要它)。

最佳答案

与您的同事相比,您更接近用 Java 实现单例模式的通常方式。请看一下 Wikipedia .在那里您会找到 3 种最常见的 Java 实现:

传统简单方式

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

“Bill Pugh 的解决方案”

public class Singleton {
    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder { 
        public static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

使用同步的传统简单方式

public class Singleton {
    // volatile is needed so that multiple threads can reconcile the instance
    // semantics for volatile changed in Java 5.
    private volatile static Singleton singleton;

    private Singleton() {}

    // synchronized keyword has been removed from here
    public static Singleton getSingleton() {
        // needed because once there is singleton available no need to acquire
        // monitor again & again as it is costly
        if (singleton == null) {
            synchronized (Singleton.class) {
                // this is needed if two threads are waiting at the monitor at the
                // time when singleton was getting instantiated
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

它们都没有使用单独的 initObject() 方法(初始化应该在私有(private)构造函数中进行)。另请注意,如果您有一个单独的公共(public) initObject() 方法,您可能会遇到多线程问题...

顺便说一句,我个人更愿意使用“Bill Pugh”替代方案,但这 3 种方式都是有效的。

编辑 在 Esko 评论之后,我添加了以下实现,维基百科上没有它。我只想补充一点 1) 单例实例不像上面的 3 个选项那样延迟创建; 2) 因为它是一个枚举,所以你不能扩展任何类; 3)这非常非常奇怪。但它在 Java 社区似乎被大肆宣传,所以在这里:

枚举方式

public enum Singleton {
    INSTANCE;
    Singleton() {
        /* Your init code goes here */
    }
}

关于java - 单例类设计——空对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4110252/

相关文章:

java - Struts 2 验证方法在没有 XML 的情况下无法工作

java - 如何在多线程 Java 应用程序中安全地使用 OracleDriver.defaultConnection()?

java - Java 中的单例

java - 我们什么时候应该在 Java 中使用 Singleton 类?

java - JSONObject 使用单例

java - 以编程方式绘制选择器

java - REST API 中的 gZip 实现

java - java中使用递归的动态规划(切杆)

c++ - 如何知道谁是给定线程 ID 的父线程

C++线程死锁