Abstract: Singleton is a common design pattern in creation types. Classes in this mode have one and only one instance.

What is the singleton pattern?

When it comes to singleton patterns, you should be familiar with them because they are so common that all developers should be exposed to the first design pattern. So here’s a quick explanation of why you should use singletons: If you want your class to have only one instance object, shared globally, then you use singletons.

I like the singleton implementation

The singleton pattern is a common design pattern in creation types. Classes in this mode have one and only one instance. There are two common implementations of the singleton pattern, slacker and hunger-head, but I don’t want to discuss them here because they are so common that they are not worth discussing and thinking about.

Let’s take a look at some of the implementation mechanisms in the following ways:

Double check lock (DCL)

The code:

Development, singleton pattern, threading,




The DCL’s double locking ensures that each call to the getSingleton method is synchronized. In fact, lock everyone can understand, is to solve the problem of multi-threaded synchronization. But there’s an important point here, and it’s this line of code:

private volatile static Singleton singletonCopy the code
The reason for using volatile is explained in two ways:


1. What if you didn’t use volatile?

This seems to work, but if you look at the compiler and program instructions, it’s not reliable for the following reasons:

  1. The compiler optimizes program instructions to speed up CPU processing.
  2. Multicore cpus dynamically adjust table instruction order to speed up parallel computing power.
It’s 202 years ago, a computer has several cpus and cores, not the old days of single-core, so after Java files are compiled into bytecode instructions, your coding logic is indeed serial, and the computer will return the logical results of your programming to you according to the paradigm. But specific to the CPU to execute instructions, in order to reflect the advantages of multi-core, some instructions will do parallel processing, to speed up the running of the program.

For those of you who are curious to know when a problem might occur if volatile were not used, let me give you the order in which the problem might occur:

  1. Thread A, which calls the method to get the instance, finds that the object is not instantiated and is ready to start the instantiation.
  2. Because the compiler optimizes the program’s instructions to allow an object to point a reference to a shared variable to a partially constructed object before the constructor call is complete, the object is not fully instantiated but is no longer null.
  3. Thread B also calls the method to obtain the instance, and finds that the partially constructed object is not null, so it directly returns the object.
As for what happens when thread B returns, it can be imagined that the instantiation is not complete, which will result in a null pointer exception when the partial method is called, so it is not reliable.


2. What does volatile do?

To solve this problem, JDK1.6 or later provides this keyword so that the variables it modifiers can be visible between threads. By visible, everyone gets them from main memory, which is not explained here.


Read this: After thread B reads A volatile variable, the values of all visible shared variables become visible to thread B immediately before thread A writes to that volatile.


Corresponding to the above problem solving is: The singleton variable is null before thread A completes the initialization, and thread B reads it as null. When thread B tries to instantiate the lock, thread A obtains the lock and is instantiating it, it blocks until thread A completes the initialization and releases the lock. But since B immediately knows that it’s not null again, on the second call, it doesn’t have to go in new, it returns.

Static inner class

The code:

Static inner classes are one of my favorite implementations, obviously with less code and simpler logic. This approach uses the Classloader mechanism to ensure that only one thread is used to initialize the Singleton, avoiding the need to ensure that the thread synchronization problem. The static inner class Holder is not initialized when the Singleton class is loaded. The static inner class Holder is only initialized when the Singleton class is actively used, that is, after the getSingleton method is called. Is displayed to load the Holder class, thereby instantiating the Singleton object. This is a good option if you want to lazily load a Singleton object if it is a resource-consuming memory object.


However, the static inner class approach is not as perfect as you might think, because it does not prevent reflection and anti-sequence attacks. You can use the first two methods to construct new instances of Singleton, so it is not strictly a Singleton.

Third, the enumeration

The code:

This approach, advocated by Josh Bloch, takes advantage of enumerations to allow the JVM to handle thread safety and singleton issues, as well as to prevent deserialization and reflection.


Enumeration is the creation of an object in a static block:

Is the singleton really that good?

Advantages:

1. Provides controlled access to a unique instance.

2. Because there is only one instance, system resources are saved and system performance is improved.

Disadvantages:

1. The singleton pattern has no abstraction layer, so it is difficult to extend.

2. Singleton classes are too heavy and violate the “single responsibility principle”.


My recommendations:

The basic goal of using singletons is to save memory resources, and most Web projects introduce the Spring framework. The singletons implemented through Spring are different from the singletons described in the design pattern above. Design pattern singletons have only one instance in the entire Java application, whereas Spring singletons have only one instance in an IOC container. However, for Web applications, the Web container (Jetty or Tomcat) creates a separate servlet thread for each request from the user to handle the request, and the Interface under the Spring framework is also a singleton for each action, thus ensuring that we are using an instance.


Spring also allows lazy-init via annotations or XML, and scope can be specified to determine whether it is a global singleton or multiple instances, giving programs more options.

Of course, Spring does not guarantee thread-safety for all beans in most cases, so it is up to the developers to write our own programs to ensure thread-safety. However, in the dao bean object of the database layer that we often use, Spring uses ThreadLocal object to distinguish it from the commonly used way of locking. Instead, it uses space for time and assigns a separate copy of variables to each thread, so as to isolate the conflict between multi-thread access and data access and ensure thread safety. As for this class and this mechanism, I won’t go into detail here, because I won’t be able to cover it in this article.


Click to follow, the first time to learn about Huawei cloud fresh technology ~