Java 单件设计模式被打破了?
可能重复:Java 单件设计模式被打破了?,java,design-patterns,singleton,Java,Design Patterns,Singleton,可能重复: 我本以为下面的类是线程安全的单例,但读起来似乎不是 public class ThreadSafeSingleton { private static ThreadSafeSingleton ref; private ThreadSafeSingleton(){ } public ThreadSafeSingleton getSingletonObject(){ if(ref == null){ re
我本以为下面的类是线程安全的单例,但读起来似乎不是
public class ThreadSafeSingleton {
private static ThreadSafeSingleton ref;
private ThreadSafeSingleton(){
}
public ThreadSafeSingleton getSingletonObject(){
if(ref == null){
ref = new ThreadSafeSingleton();
}
return ref;
}
}
根据文章,唯一真正线程安全的单例是——
public class ThreadSafeSingleton {
private static ThreadSafeSingleton ref = new ThreadSafeSingleton();
private ThreadSafeSingleton(){
}
public ThreadSafeSingleton getSingletonObject(){
return ref;
}
}
这是否正确?这不是唯一的线程安全单例,但这是正确的。另一种方法是同步第一个示例中创建singleton实例的代码。但问题是您必须同步代码,这可能是问题,也可能不是问题。另一个可能的问题是单例没有延迟初始化。同样,这可能是问题,也可能不是问题,这取决于体系结构和需求。还有另一种处理这个问题的奇怪模式:。这不是唯一的线程安全单例,但这是正确的。另一种方法是同步第一个示例中创建singleton实例的代码。但问题是您必须同步代码,这可能是问题,也可能不是问题。另一个可能的问题是单例没有延迟初始化。同样,这可能是问题,也可能不是问题,这取决于体系结构和需求。还有另一种处理这个问题的奇怪模式: 如果(ref==null),两个大致同时运行的线程可能会命中
。两个线程可以看到ref
实际上是空的。然后,两个线程将创建一个新实例。然后可以给两个线程提供单独的实例。现在您有了两个不同的“singleton”对象实例
此代码段中没有防止上述竞争条件的机制
如果(ref==null)
,两个大致同时运行的线程可能会命中。两个线程可以看到ref
实际上是空的。然后,两个线程将创建一个新实例。然后可以给两个线程提供单独的实例。现在您有了两个不同的“singleton”对象实例
此代码段中没有防止上述竞争条件的机制。是的,它是正确的
在第一种情况下,如果两个线程同时调用getSingletonObject()
,则有可能最终得到两个singleton实例
在第二种情况下,该方法只返回对类加载期间创建的现有对象的引用,这是由JVM以线程安全的方式完成的
就线程安全性而言,第二种方法比第一种方法好得多。是的,它是正确的
在第一种情况下,如果两个线程同时调用getSingletonObject()
,则有可能最终得到两个singleton实例
在第二种情况下,该方法只返回对类加载期间创建的现有对象的引用,这是由JVM以线程安全的方式完成的
就线程安全性而言,第二种方法要比第一种方法好得多。是的,本文是正确的
在上面的示例中,如果该方法同时被两个函数调用,它们可能都会将ref
视为null,因为在另一个函数检查它之前,两个函数都没有完成创建和赋值
在下面的示例中,ref
在类加载时分配一次,然后任何东西都可以访问它。是的,本文是正确的
在上面的示例中,如果该方法同时被两个函数调用,它们可能都会将ref
视为null,因为在另一个函数检查它之前,两个函数都没有完成创建和赋值
在下面的示例中,ref
在类加载时分配一次,然后任何东西都可以访问它。有两种不同的方法来实现线程安全的单例对象。静态初始化(底层方法)就是其中之一
您还可以使用,synchronizegetInstance()
,甚至可以使用,只要holder变量声明为volatile
。有关更多信息,请参阅
其中,如果我必须构建一个实际的单例,我更喜欢第一种方法。否则,我喜欢在中使用作用域 有两种不同的方法来实现线程安全的单例对象。静态初始化(底层方法)就是其中之一 您还可以使用,synchronize
getInstance()
,甚至可以使用,只要holder变量声明为volatile。有关更多信息,请参阅
其中,如果我必须构建一个实际的单例,我更喜欢第一种方法。否则,我喜欢在中使用作用域 请检查右侧栏中的“相关”列表(顺便说一下,它与您键入问题标题后显示的列表完全相同)。当然,这个问题以前被问过无数次:)肯定不是唯一的线程安全方式,甚至不是最好的线程安全方式。确实,顶部不是线程安全的,而底部似乎是线程安全的。我的理解是,底部解决方案是“最佳”线程安全的单例实现(尽管最佳方案可能取决于特定的用例)。Glowcoder,你推荐哪种方式更好?@increment如何定义“最佳”?不同的解决方案有不同的权衡。如果您以后只需要对象,那么它当然不是昂贵初始化的最佳方法。@user470184,这不是实现线程安全单例的唯一方法。博客上没有这么说。有许多特定于平台的解决方案,这些解决方案将在博客文章的末尾简要介绍。特别是,如果您使用的是J2SE 5.0或更高版本,那么您可以将
volatile
与DCLP一起使用,因此也可以进行延迟初始化。请检查右侧栏中的“相关”列表(顺便说一句,该列表与您键入问题标题后显示的列表完全相同)。这个问题肯定已经被问过无数次了
if(ref == null)
{
ref = new ThreadSafeSingleton();
}
return ref;