Reputation: 93
I am referring to the solution for the Singleton Pattern by Bill Pugh on Wikipedia:
public class Singleton
{
// Private constructor prevents instantiation from other classes
private Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder
{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance()
{
return SingletonHolder.INSTANCE;
}
}
Here they have mentioned:
The inner class is referenced no earlier (and therefore loaded no earlier by the class loader) than the moment that
getInstance()
is called. Thus, this solution is thread-safe without requiring special language constructs (i.e.volatile
orsynchronized
).
However, isn't there a possibility that 2 threads would call getInstance()
at the same time, which would lead to two instances of singleton being created? Isn't it safe to use synchronized
here? If yes, where should it be used in the code?
Upvotes: 7
Views: 1780
Reputation: 570285
This idiom is known as the Initialization on Demand Holder (IODH) idiom and is discussed in Item 48 of Effective Java as reminded by Bob Lee in his great post about Lazy Loading Singletons:
Item 48: Synchronize access to shared mutable data
(...)
The initialize-on-demand holder class idiom is appropriate for use when a static field is expensive to initialize and may not be needed, but will be used intensively if it is needed. This idiom is shown below:
// The initialize-on-demand holder class idiom private static class FooHolder { static final Foo foo = new Foo(); } public static Foo getFoo() { return FooHolder.foo; }
The idiom takes advantage of the guarantee that a class will not be initialized until it is used [JLS, 12.4.1]. When the
getFoo
method is invoked for the first time, it reads the fieldFooHolder.foo
, causing theFooHolder
class to get initialized. The beauty of this idiom is that thegetFoo
method is not synchronized and performs only a field access, so lazy initialization adds practically nothing to the cost of access. The only shortcoming of the idiom is that it does not work for instance fields, only for static fields.
However, in the Second Edition of Effective Java, Joshua explains how enums can be (ab)used for writing a serializable Singleton (this should be the preferred way with Java 5):
As of release 1.5, there is a third approach to implementing singletons. Simply make an enum type with one element:
// Enum singleton - the preferred approach public enum Elvis { INSTANCE; public void leaveTheBuilding() { ... } }
This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.
Upvotes: 0
Reputation: 12049
There are two differences here that need to be noted. The first is the Singleton design pattern and the other is a singleton instance.
The Singleton design pattern is problematic due to the fact that the design pattern represents a singleton instance as is implemented using static state (which is a bad thing for a variety of reasons - especially with unit testing). The second is an instance for which there is only one instance, no matter what (like the JVM singleton implemented as an enum).
The enum version is definitely superior, when compared to the Singleton pattern.
If you don't want to implement all instances as enum
instances, then you should think about using Dependency Injection (frameworks such as Google Guice) to manage the singleton instances for the application.
Upvotes: 0
Reputation: 70204
The JLS guarantees the JVM will not initialize instance until someone calls getInstance();
and that will be thread safe because it would happen during the class initialization of SingletonHolder
.
However, since Java 5, the preferred approach involves Enum
:
// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}
Reference: Implementing the singleton pattern in Java
Upvotes: 5
Reputation: 68942
The Singleton is created when Singleton.getInstance() is called at this time the INSTANCE will be instantiated. Synchronization depends on a conrete implementation, since there are no values to modify (in this example) no synchronization is required.
Upvotes: 0
Reputation: 11279
See the "How it works", in the article "Initialization on demand holder idiom" linked from the same section.
In a nutshell, here's what happens when you call getInstance()
the first time:
SingletonHolder
it has never seen referenced before.SingletonHolder
. This includes running any static initialization, which includes the singleton instance.getInstance()
at the same time will see that SingletonHolder
is already initialized. The Java spec guarantees that class initialization is thread-safe.Upvotes: 12
Reputation: 2118
I think the idea is that Java guarantees that a class can only be initialized once, so implicitly only the first thread to access would cause this to happen
Upvotes: 0
Reputation: 83220
Here is the explanation from Wikipedia on this phenomenon (emphasis mine):
When the class Something is loaded by the JVM, the class goes through initialization. Since the class does not have any static variables to initialize, the initialization completes trivially. The static class definition LazyHolder within it is not initialized until the JVM determines that LazyHolder must be executed. The static class LazyHolder is only executed when the static method getInstance is invoked on the class Something, and the first time this happens the JVM will load and initialize the LazyHolder class. The initialization of the LazyHolder class results in static variable something being initialized by executing the (private) constructor for the outer class Something. Since the class initialization phase is guaranteed by the JLS to be serial, i.e., non-concurrent, no further synchronization is required in the static getInstance method during loading and initialization. And since the initialization phase writes the static variable something in a serial operation, all subsequent concurrent invocations of the getInstance will return the same correctly initialized something without incurring any additional synchronization overhead.
So in your example, Singleton
is "LazyHolder" and SingletonHolder
is "Something". Calling getInstance()
twice will not cause a race condition due to the JLS guarantees.
Upvotes: 3