我已经阅读了他的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
}
已经使用过几次,我对此非常熟悉。但是,当我深入探讨该主题时,发现该版本根本不是线程安全的。
这到底是什么意思?如果有多个线程访问它并创建一个新实例,会创建更多不同的实例吗?还是“安全”不再存在?
非常感谢您的回答。
答案 0 :(得分:4)
如果您不太幸运,则可以同时存在更多实例,这样它们就可以同时访问,因此两个线程都可以同时经过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,否则其他线程将不会立即看到对该共享变量的更改。代替volatile
的另一种选择是使用AtomicReference<T>
。)
答案 1 :(得分:1)
假设多个线程尝试获取单例类的实例,它们同时调用以下方法:
public static ClassSingleton getInstance() {
if(INSTANCE == null) {
INSTANCE = new ClassSingleton();
}
return INSTANCE;
}
INSTANCE == null
对于两个线程都是正确的,并且它们最终都将创建一个新实例。