Other Ways of Singleton in Java [duplicate]
Just i was thinking about the other ways of writing singleton 开发者_Go百科class. So is this class considered as a singleton class?
public class MyClass{
static Myclass myclass;
static { myclass = new MyClass();}
private MyClass(){}
public static MyClass getInstance()
{
return myclass;
}
}
as the static block run only once.
No, it is not. You didn't declare myClass
private static final
, nor the getInstance()
is static
. The code also doesn't really compile.
Here's the Singleton idiom:
public class MyClass {
private static final MyClass myClass = new MyClass();
private MyClass() {}
public static MyClass getInstance() {
return myClass;
}
}
It should be private
, so that nobody else can access it directly. It should be static
so that there's only one of it. It should be final
so that it cannot be reassigned. You also need to instantiate it directly during declaration so that you don't need to worry (that much) about threading.
If the loading is expensive and you thus rather prefer lazy loading of the Singleton, then consider the Singleton holder idiom which does initialization on demand instead of during classloading:
public class MyClass {
private MyClass() {}
private static class LazyHolder {
private static final MyClass myClass = new MyClass();
}
public static MyClass getInstance() {
return LazyHolder.myClass;
}
}
You should however put big question marks whether you need a Singleton or not. Often it's not needed. Just a static variable, an enum, a factory class and/or dependency injection is often the better choice.
Here's one more way to do it :
public enum Singleton{
INSTANCE("xyz", 123);
// Attributes
private String str;
private int i;
// Constructor
Singleton(String str, int i){
this.str = str;
this.i = i;
}
}
According to Josh Bloch's Effective Java, this is the best way to implement Singleton in Java. Unlike implementations that involve a private static instance field, which can be multiply instantiated through the abuse of reflection and/or serialization, the enum is guaranteed to be a singleton.
The main limitation with enum singletons is that they are always instantiated at class loading time and can't be lazily instantiated. So if, for example, you want to instantiate a singleton using run-time arguments, you'll have to use a different implementation (preferably using double-checked locking).
There are 3 ways to create a singleton in java.
eager initialization singleton
public class Test { private static final Test TEST = new Test(); private Test() { } public static Test getTest() { return TEST; } }
lazy initialization singleton (thread safe)
public class Test { private static volatile Test test; private Test(){} public static Test getTest() { if(test == null) { synchronized(Test.class) { if(test == null){test = new Test();} } } return test; } }
Bill Pugh Singleton with Holder Pattern (Preferably the best one)
public class Test { private Test(){} private static class TestHolder { private static final Test TEST = new Test(); } public static Test getInstance() { return TestHolder.TEST; } }
Using your example and using the GoF's way of implementing it:
public class MyClass{
private static Myclass instance;
private MyClass(){
//Private instantiation
}
public static synchronized MyClass getInstance() //If you want your method thread safe...
{
if (instance == null) {
instance = new MyClass();
}
return instance;
}
}
Hope this helps:
Here is how I do it. It is faster, because it only requires a synchronized
block when the instance is created.
public class MyClass
{
private static MyClass INSTANCE=null;
private MyClass()
{
}
public static MyClass getInstance()
{
if(INSTANCE==null)
{
synchronized(MyClass.class)
{
if(INSATCNE==null) INSTANCE=new MyClass();
}
}
return INSTANCE;
}
}
Your class (original code, before editing):
public class MyClass {
Myclass myclass;
static { myclass = new MyClass();}
private MyClass(){}
public MyClass getInstance()
{
return myclass;
}
}
is not a real singleton:
- the field
myclass
is not private, can be read and changed from outside (assuming you got an instace to do it on - the field
myclass
is not static, can not be accessed in the static constructor (compilation error) - the
getInstance()
method is not static, so you need an instance to call it
The actual code:
public class MyClass {
static Myclass myclass;
static { myclass = new MyClass();}
private MyClass(){}
public static MyClass getInstance()
{
return myclass;
}
}
still has myclass
not being private (nor final)... declaring it final would help to prevent it being unintentionally changed from inside the class.
private static final Myclass myclass;
public class singletonPattern {
private static singletonPattern obj;
public static singletonPattern getObject() {
return obj = (obj == null) ? new singletonPattern() : obj;
}
public static void main(String args[]) {
singletonPattern sng = singletonPattern.getObject();
}
}
Might be a little late to the game on this, but a basic implementation would look something like this:
public class MySingleton {
private static MySingleton INSTANCE;
public static MySingleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new MySingleton();
}
return INSTANCE;
}
...
}
Here we have the MySingleton class which has a private static member called INSTANCE, and a public static method called getInstance(). The first time getInstance() is called, the INSTANCE member is null. The flow will then fall into the creation condition and create a new instance of the MySingleton class. Subsequent calls to getInstance() will find that the INSTANCE variable is already set, and therefore not create another MySingleton instance. This ensures there is only one instance of MySingleton which is shared among all callers of getInstance().
But this implementation has a problem. Multi-threaded applications will have a race condition on the creation of the single instance. If multiple threads of execution hit the getInstance() method at (or around) the same time, they will each see the INSTANCE member as null. This will result in each thread creating a new MySingleton instance and subsequently setting the INSTANCE member.
private static MySingleton INSTANCE;
public static synchronized MySingleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new MySingleton();
}
return INSTANCE;
}
Here we’ve used the synchronized keyword in the method signature to synchronize the getInstance() method. This will certainly fix our race condition. Threads will now block and enter the method one at a time. But it also creates a performance problem. Not only does this implementation synchronize the creation of the single instance, it synchronizes all calls to getInstance(), including reads. Reads do not need to be synchronized as they simply return the value of INSTANCE. Since reads will make up the bulk of our calls (remember, instantiation only happens on the first call), we will incur an unnecessary performance hit by synchronizing the entire method.
private static MySingleton INSTANCE;
public static MySingleton getInstance() {
if (INSTANCE == null) {
synchronize(MySingleton.class) {
INSTANCE = new MySingleton();
}
}
return INSTANCE;
}
Here we’ve moved synchronization from the method signature, to a synchronized block that wraps the creation of the MySingleton instance. But does this solve our problem? Well, we are no longer blocking on reads, but we’ve also taken a step backward. Multiple threads will hit the getInstance() method at or around the same time and they will all see the INSTANCE member as null. They will then hit the synchronized block where one will obtain the lock and create the instance. When that thread exits the block, the other threads will contend for the lock, and one by one each thread will fall through the block and create a new instance of our class. So we are right back where we started.
private static MySingleton INSTANCE;
public static MySingleton getInstance() {
if (INSTANCE == null) {
synchronized(MySingleton.class) {
if (INSTANCE == null) {
INSTANCE = createInstance();
}
}
}
return INSTANCE;
}
Here we issue another check from INSIDE the block. If the INSTANCE member has already been set, we’ll skip initialization. This is called double-checked locking.
This solves our problem of multiple instantiation. But once again, our solution has presented another challenge. Other threads might not “see” that the INSTANCE member has been updated. This is because of how Java optimizes memory operations. Threads copy the original values of variables from main memory into the CPU’s cache. Changes to values are then written to, and read from, that cache. This is a feature of Java designed to optimize performance. But this creates a problem for our singleton implementation. A second thread — being processed by a different CPU or core, using a different cache — will not see the changes made by the first. This will cause the second thread to see the INSTANCE member as null forcing a new instance of our singleton to be created.
private static volatile MySingleton INSTANCE;
public static MySingleton getInstance() {
if (INSTANCE == null) {
synchronized(MySingleton.class) {
if (INSTANCE == null) {
INSTANCE = createInstance();
}
}
}
return INSTANCE;
}
We solve this by using the volatile keyword on the declaration of the INSTANCE member. This will tell the compiler to always read from, and write to, main memory, and not the CPU cache.
But this simple change comes at a cost. Because we are bypassing the CPU cache, we will take a performance hit each time we operate on the volatile INSTANCE member — which we do 4 times. We double-check existence (1 and 2), set the value (3), and then return the value (4). One could argue that this path is the fringe case as we only create the instance during the first call of the method. Perhaps a performance hit on creation is tolerable. But even our main use-case, reads, will operate on the volatile member twice. Once to check existence, and again to return its value.
private static volatile MySingleton INSTANCE;
public static MySingleton getInstance() {
MySingleton result = INSTANCE;
if (result == null) {
synchronized(MySingleton.class) {
result = INSTANCE;
if (result == null) {
INSTANCE = result = createInstance();
}
}
}
return result;
}
Since the performance hit is due to operating directly on the volatile member, let’s set a local variable to the value of the volatile and operate on the local variable instead. This will decrease the number of times we operate on the volatile, thereby reclaiming some of our lost performance. Note that we have to set our local variable again when we enter the synchronized block. This ensures it is up to date with any changes that occured while we were waiting for the lock.
I wrote an article about this recently. Deconstructing The Singleton. You can find more info on these examples and an example of the "holder" pattern there. There is also a real-world example showcasing the double-checked volatile approach. Hope this helps.
Singloton class is the class where you get the same object every time. When you want to restrict a class from creating more than one object the we need the Singleton Class.
For example :
public class Booking {
static Booking b = new Booking();
private Booking() { }
static Booking createObject() { return b; }
}
To create object of this class we can use :
Booking b1, b2, b3, b4;
b1 = Booking.createObject();
b2 = Booking.createObject();
Booking b1, b2, b3, b4;
b1 = Booking.createObject();
b2 = Booking.createObject();
b1
and b2
are referring to same object.
You should think about the following properties while creating a singleton class
- Reflection
- Multi threading
- Clone
- Serialization
if no Clone or Serialization interfaces in your class, i think the following class is best as singleton class.
public class JavaClass1 {
private static JavaClass1 instance = null;
private JavaClass1() {
System.out.println("Creating -------");
if (instance != null) { // For Reflection
throw new RuntimeException("Cannot create, please use getInstance()");
}
}
public static JavaClass1 getInstance() {
if (instance == null) {
createInstance();
}
return instance;
}
private static synchronized void createInstance() { // for multithreading
if (instance == null) {
instance = new JavaClass1();
}
}}
精彩评论