In this article I want to touch on the topic of one of the most common patterns of object-oriented programming - Singleton. But in this case I will not describe the advantages / disadvantages and areas of application of this pattern, but I will try to present my view on its implementation in JAVA.
General informationThe Singleton pattern ensures that a class has only one instance, and provides a global access point to it.
Application area1.) The system must have no more than one instance of a given class.
2.) The instance should be easily accessible to all clients of this class.
3.) Creating an on demand object, that is, when it is needed for the first time, and not during system initialization.
')
Implementation (JAVA):At the moment there are several implementation options with their own advantages and disadvantages. We will try to understand them now.
Option one is the simplest one that comes to mind immediately after understanding the problem.

This solution has a single drawback - it does not work in a multi-threaded environment and therefore does not work in most cases. The solution is suitable only for single-threaded applications.
Do not worry, tell you, and propose the following solution.
Option two:
And you will be right, because we solved the problem of multithreading, but lost two important things:
1. Lazy initialization (The instance object will be created by the classloader during class initialization)
2. There is no possibility to handle exceptions during a constructor call.
The solution is suitable for multi-threaded applications, provided there is no danger of exceptional situations in the constructor and no need for lazy initialization.
Next, there are 2 solutions.
1.) Using the internal class (Bill Pugh solution
“Initialization on Demand Holder” ).
2.) Using synchronization.
Let's start with Bill Pew.
Option three:“Initialization on Demand Holder”

In this case, we have completely solved the problem of lazy initialization - the object is initialized by the first call to the getInstance () method. But we still have a problem with handling exceptional situations in the constructor. So, if the class constructor does not cause any concerns about creating exceptional situations, then you can safely use this method.
SynchronizationI would like to pay special attention to this part. One could approach this issue with the heading "synchronized - myths and reality".
And so, the most straightforward method.
Option Four:
This option has only one drawback. Synchronization is useful only once, at the first call to getInstance (), after that, each time, when accessing this method, synchronization simply takes time. What can you say about this? Well, firstly, if the getInstance () call does not occur often enough (which means “quite often” you decide), then this method takes precedence over the others - it is simple, understandable, is lazily initialized, and allows you to handle exceptional situations in the constructor. And secondly, synchronization in Java has ceased to be burdensomely slow as far as its fear. Well, what else is necessary for happiness?
Now we will consider a synchronized solution, in which we will try to solve the problem that arose in the previous version.
The most common method is
Double-Checked Locking . In its original version:
Does not work! Why? This is a separate topic, but for those interested, I can advise you to read this article
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html .
But do not completely despair, in JAVA 5, the problem was solved using the
volatile modifier . At the moment, the solution looks like this:
Option Five:
Although this option looks like an ideal solution, it is not recommended to use it. Comrade
Allen Holub noticed that using a
volatile modifier can lead to performance problems on multiprocessor systems. But it's up to you to decide.
Here, in general, and all the common options for the implementation of this pattern. But, this does not end the pitfalls of Singleton. There are several other points that need to be taken into account during the design of an application using Singleton.
Underwater rocks1.
InheritanceIn the overwhelming majority of cases, in Singleton classes, inheritance is not necessary and, moreover, unnecessary and is a consequence of over-design. Yes, and the implementation of inheritance has certain difficulties, given that the instance itself and the getInstance () method are static.
Therefore, I recommend using the final modifier and prohibiting the inheritance of this class if there is no special need for the opposite.
2.
Two or more virtual machinesEach virtual machine creates its own copy of the Singleton object. And although at first glance this looks obvious, in many distributed systems, such as EJB, JINI and RMI, things are not so simple. When intermediate levels hide (make transparent) distributed technologists, it is difficult to say where and when the object is initialized.
3.
Different Class LoaderWhen 2 class loader downloads a class, each of them can create its own copy of Singleton (in cases where the instance is initialized by the class loader). This is especially true in the use of servlets (servlet), since in some implementations of application servers (application server) each servlet has its own class loader.
There are a number of problems that are less relevant (such as the technology of reflection and the implementation of Cloneable and Serializable interfaces), and will not be considered by me because of their exoticism in the application of Singleton classes. But, in any case, I will be happy to answer any questions about this material.
Here, in general, and all the key points that I wanted to highlight in this article. It remains only to note that this material does not claim to be the ultimate truth and allows for the existence of points of view that differ from the point of view of the author. And even more, any comments are welcome and will be taken into account.
Thanks for attention.