1

我已经阅读了他的 Singleton 的基本 Java 实现,因为我将在我的课程中介绍设计模式:

public final class ClassSingleton {

    private static ClassSingleton INSTANCE;
    private String info = "Initial info class";

    private ClassSingleton() {        
    }

    public static ClassSingleton getInstance() {
        if(INSTANCE == null) {
            INSTANCE = new ClassSingleton();
        }

        return INSTANCE;
    }

    // getters and setters
}

用过几次,就很熟悉了。然而,当我深入研究这个话题时,我发现这个版本根本不是线程安全的。

这到底是什么意思?如果多个线程访问它并创建一个新实例,是否会创建更多不同的实例?或者“安全”在哪里不复存在?

提前感谢您的回答。

4

2 回答 2

5

如果您不幸同时访问它,那么可能存在更多实例,因此两个线程if(INSTANCE == null)同时通过。

这就是为什么你通常会这样做

public final class ClassSingleton {

    private static volatile ClassSingleton INSTANCE;
    private String info = "Initial info class";

    private ClassSingleton() {        
    }

    private static final Object lock = new Object();

    public static ClassSingleton getInstance() {
        if(INSTANCE == null) {
            synchronized(lock) {
                if(INSTANCE == null) {
                    INSTANCE = new ClassSingleton();
                }
            }
        }

        return INSTANCE;
    }

    // getters and setters
}

因为如果 的监视器中已经有另一个线程,它会强制线程等待lock,从而初始化单例。

(编辑:另外,我很高兴重复的问题是“为什么要使用 volatile”,我认为它应该是必要的,所以我添加了它:p 否则其他线程不会看到这个共享变量的立即更改。另一个选项改为ofvolatile将使用AtomicReference<T>.)

于 2019-01-04T10:01:05.463 回答
1

假设多个线程尝试获取单例类的实例,它们同时调用以下方法:

public static ClassSingleton getInstance() {
        if(INSTANCE == null) {
            INSTANCE = new ClassSingleton();
        }
    return INSTANCE;
}

INSTANCE == null两个线程都是如此,它们最终都会创建一个新实例。

于 2019-01-04T10:01:11.670 回答