Java 中的线程安全单例
关于 Singletons 的维基百科文章提到了一些在 Java 中实现该结构的线程安全方法。对于我的问题,让我们考虑具有冗长初始化过程并且同时被多个线程访问的单例。
首先,这个未提及的方法是否是线程安全的?如果是,它是在什么上同步的?
public class Singleton {
private Singleton instance;
private Singleton() {
//lots of initialization code
}
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
其次,为什么下面的实现是线程安全的并且初始化是惰性的?如果两个线程同时进入 getInstance()
方法,到底会发生什么?
public class Singleton {
private Singleton() {
//lots of initialization code
}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
最后,在第二个示例中,如果一个线程首先获取一个实例,另一个线程获取一个实例并尝试在第一个线程中的构造函数完成之前对其执行操作,该怎么办?那么你会进入不安全状态吗?
The wikipedia article on Singletons mentions a few thread safe ways to implement the structure in Java. For my questions, let's consider Singletons that have lengthy initialization procedures and are acccessed by many threads at once.
Firstly, is this unmentioned method thread-safe, and if so, what does it synchronize on?
public class Singleton {
private Singleton instance;
private Singleton() {
//lots of initialization code
}
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
Secondly, why is the following implementation thread safe AND lazy in initialization? What exactly happens if two threads enter the getInstance()
method at the same time?
public class Singleton {
private Singleton() {
//lots of initialization code
}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
Finally, in the second example, what if one thread gets an instance first and another thread gets an instance and tries to perform actions on it before the constructor has finished in the first thread? Can you get into an unsafe state then?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
答案 1:
静态同步
方法使用类对象作为锁 - 即本例中的Singleton.class
。答案2:java语言,除其他外:
这两个事实意味着内部静态类
SingletonHolder 在调用 getInstance() 方法之前不会加载。此时,在进行调用的线程有权访问它之前,该类的静态实例将作为类加载的一部分进行实例化。
这一切都意味着我们有安全的延迟加载,并且不需要任何同步/锁定!
此模式是用于单例的模式。它击败了其他模式,因为 MyClass.getInstance() 是单例事实上的行业标准 - 每个使用它的人都会自动知道他们正在处理单例(对于代码,显而易见总是好的),所以这个模式有正确的 API 和底层的正确实现。
顺便说一句,Bill Pugh 的文章在理解单例时值得一读,以保证完整性模式。
Answer 1:
static synchronized
methods use the class object as the lock - ie in this caseSingleton.class
.Answer 2: The java language, among other things:
These two facts mean that the inner static class
SingletonHolder
is not loaded until the getInstance() method is called. At that moment, and before the thread making the call is given access to it, the static instance of that class is instantiated as part of class loading.This all means we have safe lazy loading, and without any need for synchronization/locks!
This pattern is the pattern to use for singletons. It beats other patterns because
MyClass.getInstance()
is the defacto industry standard for singletons - everyone who uses it automatically knows that they are dealing with a singleton (with code, it's always good to be obvious), so this pattern has the right API and the right implementation under the hood.btw Bill Pugh's article is worth reading for completeness when understanding singleton patterns.