Simplified Singleton Pattern in Java

By default, the singleton method is as follows:

class MyClass { private static MyClass instance; public static MyClass getInstance() { if (instance == null) { instance = new MyClass(); } return instance; } } 

In an old project, I tried to simplify the notation:

 class MyClass { private static final MyClass instance = new MyClass(); public static MyClass getInstance() { return instance; } } 

But that sometimes fails. I just never knew why, and I did the default. Creating SSCCE for publication here today, I realized that the code is working.

So, I would like to know the opinions. Is this an alert error code? Is there a chance that the second approach will return null? I'm going crazy?

- Although I don’t know if the right answer is for every case, this is really an interesting answer @Alfred: I would also like to note that the singleton are testing a nightmare and that, according to the big guys, you should use the Google injection infrastructure.

+4
source share
8 answers

Recommended ( Effective Java 2nd ed ) is to make a "single rename pattern":

 enum MyClass { INSTANCE; // rest of singleton goes here } 

The key concept here is that enum values ​​are single, like singleton. So, having made an unambiguous listing, you just made yourself a singleton. The beauty of this approach is that it is completely thread safe, and also protected from any kind of loopholes that will allow people to create other instances.

+8
source

The first solution (I believe) is not thread safe.

The second solution is (I believe) thread safe, but may not work if you have complex initialization dependencies in which MyClass.getInstance() is called before the static MyClass initializations are complete. This is probably the problem you saw.

Both solutions allow someone to create another instance of your (essentially) singleton class.

More reliable solution:

 class MyClass { private static MyClass instance; private MyClass() { } public synchronized static MyClass getInstance() { if (instance == null) { instance = new MyClass(); } return instance; } } 

In a modern JVM, the cost of acquiring a lock is minimal, provided that there is no competition over the lock.

EDIT @Nate makes my statement about static initialization order, which can cause problems. Consider the following (pathological) example:

 public ClassA { public static ClassB myB = ClassB.getInstance(); public static ClassA me = new ClassA(); public static ClassA getInstance() { return me; } } public ClassB { public static ClassA myA = ClassA.getInstance(); public static ClassB me = new ClassB(); public static ClassB getInstance() { return me; } } 

There are two possible initialization options for these two classes. Both results invoke a static method that is called before the static method class initialization has been performed. This will initialize ClassA.myB or ClassB.myA to null .

In practice, the cyclic dependencies between statics are less obvious. But the fact remains: if there is a cyclic dependency: 1) the Java compiler will not be able to tell you about it, 2) the JVM will not tell you about it. Rather, the JVM will silently choose the initialization order without "understanding" the semantics of what you are trying to do ... maybe something unexpected / wrong.

EDIT 2 . This is described in JLS 12.4.1 as follows:

As the example in section 8.3.3.3 shows, the fact that the initialization code is unlimited allows you to create examples where the value of a class variable can be observed when it still has an initial default value before its initialization expression will be but such examples in practice are rare. (Such examples can also be constructed, for example, to initialize variables, see the Example at the end of Β§ 12.5). Full language permissions are available in these initializers; programmers should exercise some caution ....

+4
source

The second example is preferable since the first is not thread safe (as indicated in the comments). The first example uses the lazy instance method (or lazy initialization), which ensures that a Singleton instance is not created if it is not really needed. This is not really required in Java because of the way Java handles class loading and static initialization of instance variables.

+3
source

I would also like to note that singletons are testing a nightmare and that, according to the big guys, you should use the google dependency injection infrastructure .

+2
source

Remember that to provide a singleton property, you need to declare a private constructor.

The second case could be even simpler with just

 class MyClass { public static final MyClass instance = new MyClass(); private MyClass() { super() } } 

`

+1
source

As others have noted, the former is not thread safe. Do not worry about this, since the second one is excellent, and will only instantiate an object with a MyClass link. He then makes a reference ending, which better reflects the intention.

Just make sure the ad

 private static final MyClass INSTANCE = new MyClass(); 

is the first static declaration in your class to avoid the risk of calling getInstance () or INSTANCE before initializing it.

+1
source

Do not forget the SingletonHolder template. See this SO question.

+1
source

I do not know the answers to your questions, but here is how I can structure the same thing.

 class MyClass { private static MyClass instance; static { instance = new MyClass(); } private MyClass() { } public static MyClass getInstance() { return instance; } } 
0
source

Source: https://habr.com/ru/post/1303306/


All Articles