Copyright belongs to the author, any form of reprint please contact the author to obtain authorization and indicate the source.

Singleton pattern principle

What is a singleton?

Some objects we only need one such as thread pool, cache dataSource, hardware device, etc. If there are multiple instances, it will cause problems of conflicting and inconsistent results. After all, you have what I have, but what you have and what I have may not be exactly the same, but the same. Using the singleton pattern ensures that a class has at most one instance and provides a global access point.

public class Test {
    public class ABC {
        public ABC() {
        }

//        private ABC// ABC n1 = new ABC(); // ABC n1 = new ABC(); } public class CDB { publicCDB() {
            ABC n1, n2;
            n1 = new ABC();
            n2 = new ABC();
            System.out.println("CBD: " + (n1 == n2));    //false
        }
    }

    public static void main(String[] args) {
        ABC n1, n2;
        n1 = new Test().new ABC();
        n2 = new Test().new ABC();
        System.out.println("main: " + (n1 == n2));   //falsenew Test().new CDB(); }}Copy the code

So what method can make every new object is the same, look at the following singleton pattern class diagram, you can find some ideas!

The Singleton (single)
Static uniqueInstance (static unique object declaration)
Private Singleton () (Private instantiation method)
Static getInstance() (global access point)

Coding of actual combat

With that in mind, let’s write a simple singleton pattern code that looks like this:

public class Singleton { private static Singleton uniqeInstance = null; // Static variable privateSingletonPublic static Singleton () {// public static Singleton ()getInstance() {
        if (uniqeInstance == null) {
            uniqeInstance = new Singleton();
        }
        returnuniqeInstance; }}Copy the code

Static variables are classes that do not belong to any instance objects, so they only have one copy in memory. During class loading, the JVM allocates memory for static variables once. ===> Java static keyword description

We imagine this scenario: a food factory, the factory is only one, and then the factory also have only one pot, after making a batch of food to make the next batch, this time our food factory object is a singleton, the following is the simulation of the implementation code, the code of the singleton implementation and the simple implementation, optimized processing, will explain why later to optimize

public class ChocolateFactory { private boolean empty; // Private Boolean boiled; Public volatile static ChocolateFactory uniqueInstance = null; privateChocolateFactory() {
        empty = true; // The pan is empty boiled =false; } public static ChocolateFactorygetInstance() {
        if (uniqueInstance == null) {
            synchronized (ChocolateFactory.class) {
                if(uniqueInstance == null) { uniqueInstance = new ChocolateFactory(); }}}returnuniqueInstance; } // The first step is to fill public voidfill() {
        if(empty) {// The pot is empty // Add raw chocolate action empty =false; // The pan is full, not empty boiled =false; }} // Step 3 pour out public voiddrain() {
        if((! // The pot is not empty and has been heated // out of the chocolate action empty =true; }} // The second step is to heat public voidboil() {
        if((! empty) && (! // The pan is not empty, not heated // boiled =true; // Already heated}}}Copy the code

Problems and optimization of singleton pattern

The problem

In the case of multithreading, there’s this notion of time slices, CPU contention, and that’s exactly where singleton patterns can go wrong. What can go wrong? Take the food processing code

public synchronized static ChocolateFactory getInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new ChocolateFactory();
       }
       return uniqueInstance;
   }
Copy the code

In the case of multiple threads two objects are instantiated

Optimal solution

Synchronized getInstance method

If (uniqueInstance == null) thread 1 has no new object. Thread 2 also goes to if (uniqueInstance == null), finds no object instance, also intends to instantiate the object; Finally thread 1 thread 2 will execute uniqueInstance = new ChocolateFactory(); At this point, you can prefix the getInstance() method with the synchronized modifier, but this can be costly when multiple calls are frequent.

Eager to create instance

public class ChocolateFactory { public static ChocolateFactory uniqueInstance = new ChocolateFactory(); Public static ChocolateFactorygetInstance() {
       if (uniqueInstance == null) {
           uniqueInstance = new ChocolateFactory();
       }
       returnuniqueInstance; }}Copy the code

public static ChocolateFactory uniqueInstance = new ChocolateFactory(); If (uniqueInstance == null) is false; if (uniqueInstance == null) is false; However, if the pair of singletons is not used anywhere in the application, using this method consumes some memory space

Double check locking (best)

Public class ChocolateFactory {// Volatile variable. Each time a thread uses a volatile variable, it reads the value of the variable. public volatile static ChocolateFactory uniqueInstance = null; public static ChocolateFactorygetInstance() {
        if (uniqueInstance == null) {
            synchronized (ChocolateFactory.class) {
                if(uniqueInstance == null) { uniqueInstance = new ChocolateFactory(); }}}returnuniqueInstance; }}Copy the code

Public volatile static ChocolateFactory uniqueInstance = null; The object is not initialized at application startup, saving memory. Secondly, synchronized code blocks are determined by if (uniqueInstance == NULL) {}, and only if the conditions are met will the synchronized method be entered, reducing performance consumption.

supplement

Enumeration implements the singleton principle