如果 Singleton 不是线程安全的,这到底意味着什么?

What does it exactly mean if a Singleton is not thread-safe?

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

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
}

用过几次,比较熟悉。然而,当我深入讨论这个话题时,我发现这个版本根本不是线程安全的。

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

提前感谢您的回答。

更多的实例可以 可能 存在,如果你足够不幸,它被同时访问,所以两个线程同时通过 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 的监视器中已经有另一个线程,它会强制一个线程等待,初始化单例。

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

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

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

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