Singleton Pattern

Singleton mode: To ensure that only one instance of a class in the system is generated, mainly to solve the frequent creation and destruction of a globally used class.

benefit

  1. Time benefit - Omits the time to frequently create an object of a common class
  2. Space benefits - reduce memory usage frequency, reduce GC pressure

Singleton pattern role

Role effect
singleton class Provides a factory for singletons, returning singletons
user Get and use a singleton class object

Notice

1. A singleton class can only have one instance.
2. A singleton class must create its own unique instance by itself.
3. The singleton class must provide this instance to all other objects.

Hungry Chinese

Advantages: no locks, higher execution efficiency!
Disadvantages: Initialize when the class is loaded, wasting memory!

Based on the classloader mechanism to avoid multi-threaded synchronization problems, the instance is instantiated when the class is loaded, and the lazy loading effect cannot be achieved!

public class Singleton {  
    
    private Singleton (){}  // private ensures that the singleton will not be instantiated within other code in the system
    private static Singleton instance = new Singleton();
    // The static ally decorated method is called to instantiate the singleton object when the class is loaded (that is, as long as the class is loaded, the singleton object is automatically instantiated to waste space
    public static Singleton getInstance() {  
    return instance;  
    }  
}

lazy

Advantages: The singleton object is only created when the getInstance() method is called for the first time
Disadvantages: In order to ensure thread safety, the volatile and synchronized keywords need to be added to ensure thread safety, but each access needs to be synchronized, which affects performance and consumes more resources

public class LazySingleton
{
    private static volatile LazySingleton instance=null;    //Ensure that instance is synchronized in all threads
    private LazySingleton(){}    //private to prevent the class from being instantiated externally
    public static synchronized LazySingleton getInstance()
    {
        //add synchronization before the getInstance method
        if(instance==null)
        {
            instance=new LazySingleton();
        }
        return instance;
    }
}
/* Introducing the synchronization keyword in order to use lazy loading reduces system performance*/

lazy refactoring

The singleton pattern uses the inner class to maintain the instance of the singleton, and the inner class is not instantiated when the Singleton is loaded. Only when the getInstance method is called, the inner class will be loaded to initialize the singleton object

Using inner classes to implement singletons can do lazy loading without using synchronization keywords, which is a perfect implementation

public class Singleton {
    private Singleton(){}

    // The inner class SingletonHolder implements singleton object initialization
    private static class SingletonHolder{
        private static Singleton singleton = new Singleton();
    }

    public static Singleton getInstance(){
        // Call the inner class to get the singleton object directly
        return SingletonHolder.singleton;
    }
}

example

  • DBConnector mocks singleton class
public class DBConnector {
    private DBConnector(){} // Private constructor, which prohibits the creation of singleton objects in other classes

    private static class DBConnectorHolder{
        private static final DBConnector dbConnector = new DBConnector();
    }

    public static DBConnector getInstance(){
        return DBConnectorHolder.dbConnector;
    }
}

  • test
public class TestDemo {
    public static void main(String[] args) {
        DBConnector dbConnector01 = DBConnector.getInstance();
        DBConnector dbConnector02 = DBConnector.getInstance();
        System.out.println("dbConnector01 memory address: " + dbConnector01.toString());
        System.out.println("dbConnector02 memory address: " + dbConnector02.toString());

        System.out.println("dbConnector01 of hashcode: " + dbConnector01.hashCode());
        System.out.println("dbConnector02 of hashcode: " + dbConnector02.hashCode());

        System.out.println(dbConnector01 == dbConnector02);
    }
}
// output
dbConnector01 memory address: ink.openmind.base01.DBConnector@1c53fd30
dbConnector02 memory address: ink.openmind.base01.DBConnector@1c53fd30
dbConnector01 of hashcode: 475266352
dbConnector02 of hashcode: 475266352
true

Posted by spelman07 on Sun, 15 May 2022 13:22:49 +0300