Singleton in java
我只是在某个地方读了下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class SingletonObjectDemo { private static SingletonObjectDemo singletonObject; // Note that the constructor is private private SingletonObjectDemo() { // Optional Code } public static SingletonObjectDemo getSingletonObject() { if (singletonObject == null) { singletonObject = new SingletonObjectDemo(); } return singletonObject; } } |
我需要知道这部分的需求是什么:
1 2 3 | if (singletonObject == null) { singletonObject = new SingletonObjectDemo(); } |
如果我们不使用这部分代码呢?还有一个单一的
关于惰性初始化与渴望初始化
更明确的版本如下:
1 2 3 4 5 6 7 8 9 10 | private boolean firstTime = true; private Stuff stuff; public Stuff gimmeStuff() { if (firstTime) { firstTime = false; stuff = new Stuff(); } return stuff; } |
当第一次调用
因此,
- 维基百科/延迟初始化
- 维基百科/按需初始化持有者习语
螺纹安全
需要说的是,代码片段不是线程安全的。如果有多个线程,那么在某些竞争条件下,可以多次调用
一种解决办法是采用
不用说,正确执行单例模式并不是一件小事。
也见- SuffeWorks/Java:双重检查锁定和单件模式——对这种破缺编程习语的全面考察
- 维基百科/双重检查锁定
相关问题
- 同步块与同步方法?
有效Java第二版
书中对这些主题的论述如下:
第71项:明智地使用延迟初始化
As is the case for most optimizations, the best advice for lazy initialization is"don't do it unless you need to". Lazy initialization is a double-edged sword. It decreases the cost of initializing a class or creating an instance, at the expense of increasing the cost of accessing a lazily initialized field. Depending on what fraction of lazily initialized fields eventually require initialization, how expensive it is to initialize them, and how often each field is accessed, lazy initialization (like many"optimizations" actually harm performance).
In the presence of multiple threads, lazy initialization is tricky. If two or more threads share a lazily initialized field, it is critical that some form of synchronization be employed, or severe bugs can result.
Under most circumstances, normal initialization is preferable to lazy initialization.
第3项:使用私有构造函数或
As of release 1.5. there is a third approach to implementing singletons. Simply make an enum type with one element. [...] This approach is functionally equivalent to the
public field approach, except that it's more concise, provides the serialization mechanism for free, and provides ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection-based attacks.[...] A single-element enum type is the best way to implement a singleton.
相关问题
关于EDOCX1·14的单/ Java实现:
- 爪哇实现单模式的有效方法
- JavaEnm SuntLon
- 比较JavaEnm成员:= =或均衡器()?
- 单件螺纹安全
关于单件模式的优点和备选方案:
- 关于设计模式:何时使用单例?
- 单例程序设计的目的
- 单身汉有什么不好的
- 单身汉:好的设计还是拐杖?
- 单件的替代品是什么
- 单人间:怎么用
这个类有一个保存单例实例的字段
1-使用声明对对象进行了预先初始化-
1 | private static SingletonObjectDemo singletonObject = new SingletonObjectDemo(); |
这将导致在加载类时初始化singleton对象。这种策略的缺点是,如果您有许多单例,那么它们都将被初始化并占用内存,即使它们还不需要。
2-对对象进行延迟初始化,即在第一次调用
1 2 | // note that this initializes the object to null by default private static SingletonObjectDemo singletonObject; |
…
1 2 3 | if (singletonObject == null) { singletonObject = new SingletonObjectDemo(); } |
这样可以保存您的内存,直到真正需要单件。这种策略的缺点是,第一次调用方法时,响应时间可能稍差,因为在返回方法之前必须初始化obejct。
What if we do not use this part of code ? There would still be a single copy of SingletonObjectDemo, why do we need this code then ?
其思想是延迟加载单例,即仅在实际需要时加载实例。你为什么要这么做?好吧,Bob Lee在Lazy Loading Singletons中很好地总结了这一点:
In production, you typically want to eagerly load all your singletons so you catch errors early and take any performance hit up front, but in tests and during development, you only want to load what you absolutely need so as not to waste time.
但是您所显示的实现是中断的,它不是线程安全的,并且两个并发线程实际上可以创建两个实例。使懒惰加载的单实例线程安全的最佳方法是使用初始化按需保持器(IODH)习惯用法,该习惯用法非常简单,同步开销为零。引用有效的Java,项目71:明智地使用惰性初始化(强调不是我的):
If you need to use lazy initialization for performance on a
static field, use the lazy
initialization holder class idiom.
This idiom (also known as the
initialize-on-demand holder class idiom) exploits the guarantee that a
class will not be initialized until it
is used [JLS, 12.4.1]. Here’s how it
looks:
1
2
3
4
5 // Lazy initialization holder class idiom for static fields
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
static FieldType getField() { return FieldHolder.field; }When the
getField method is invoked
for the first time, it reads
FieldHolder.field for the first
time, causing theFieldHolder class
to get initialized. The beauty of this
idiom is that thegetField method is
not synchronized and performs only a
field access, so lazy initialization
adds practically nothing to the cost
of access. A modern VM will
synchronize field access only to
initialize the class. Once the class
is initialized, the VM will patch the
code so that subsequent access to the
field does not involve any testing or
synchronization.
也见
- 项目66:同步对共享可变数据的访问-有效Java第二版
- 项目71:使用惰性初始化,明智有效的Java第二版
- 新的内存模型是否解决了"双重检查锁定"问题?
这两行检查是否创建了一个且只有一个singleton,如果没有,它们将创建singleton实例。如果实例已经存在,则不执行任何操作,并返回该实例。单例实例是第一次按需创建,而不是在应用程序初始化时创建。
请注意,您的代码包含一个争用条件错误。当两个线程同时进入时,可以分配两次singleton对象。这可以通过同步以下方法来解决:
1 2 3 4 5 6 | public static synchronized SingletonObjectDemo getSingletonObject() { if (singletonObject == null) { singletonObject = new SingletonObjectDemo(); } return singletonObject; } |
顺便说一句,回到你的问题上来,行:
1 | private static SingletonObjectDemo singletonObject; |
声明一个静态引用,但它不会直接分配一个实例,引用由Java编译器设置为EDCOX1×1。
给定的类在被请求之前不会创建对象的第一个实例。
如果删除这两行代码,就永远不会实际创建初始实例,因此始终返回
首先,singletonObject设置为空。singleton背后的思想是,当有人调用getsingletonObject()时,第一次初始化该对象。如果不在该部分调用构造函数,则变量将始终为空。
本代码
- 负责创建第一个对象
- 阻止创建另一个