02. Design Pattern - Singleton Pattern

 

What is the singleton pattern?

 Guarantees that there is only one instance of a class, and provides an access point to this global.

Application scenarios of the singleton pattern

1. Windows' Task Manager (task manager) is a very typical singleton mode (this is very familiar), think about it, can you open two windows task managers? If you don't believe me, try it yourself~

2. Windows' Recycle Bin (recycle bin) is also a typical singleton application. During the whole system operation, the recycle bin maintains only one instance.

3. The counter of the website is generally implemented in a singleton mode, otherwise it is difficult to synchronize.

4. The log application of the application is generally implemented in the singleton mode. This is generally because the shared log file is always open, because there can only be one instance to operate, otherwise the content is not easy to append.

5. The reading of the configuration object of the web application generally also applies the singleton mode, this is because the configuration file is a shared resource.

6. The design of the database connection pool generally adopts the singleton mode, because the database connection is a kind of database resource. The use of database connection pools in database software systems is mainly to save the efficiency loss caused by opening or closing database connections. This efficiency loss is still very expensive, because the use of singleton mode for maintenance can greatly reduce this loss. .

7. The design of multi-threaded thread pools generally adopts the singleton mode, because the thread pool needs to facilitate the control of the threads in the pool.

8. The file system of the operating system is also a specific example of the implementation of the large singleton pattern. An operating system can only have one file system.

9. HttpApplication is also a typical application of a unit case. Those who are familiar with the entire request life cycle of ASP.Net (IIS) should know that HttpApplication is also a singleton pattern, and all HttpModules share an instance of HttpApplication.

Advantages and disadvantages of the singleton pattern

advantage:

    1. In the singleton pattern, the active singleton has only one instance, and all instantiations of the singleton class get the same instance. This prevents other objects from instantiating themselves, ensuring that all objects access an instance

    2. The singleton mode has a certain scalability. The class itself controls the instantiation process, and the class has corresponding scalability in changing the instantiation process.

    3. Provides controlled access to unique instances.

    4. Since there is only one object in the system memory, system resources can be saved, and the singleton mode can undoubtedly improve the performance of the system when objects need to be frequently created and destroyed.

    5. Allow a variable number of instances.

    6. Avoid multiple occupation of shared resources.

shortcoming:

    1. It is not suitable for changing objects. If the same type of objects always change in different use case scenarios, the singleton will cause data errors and cannot save each other's state.

    2. Since there is no abstraction layer in the simple interest pattern, it is very difficult to extend the singleton class.

    3. The responsibility of the singleton class is too heavy, which violates the "single responsibility principle" to a certain extent.

    4. Abusing singletons will bring some negative problems. For example, in order to save resources, the database connection pool object is designed as a singleton class, which may lead to too many programs sharing connection pool objects and connection pool overflow; if the instantiated object If it is not used for a long time, the system will consider it as garbage and be recycled, which will lead to the loss of object state.

How to create a singleton

Hungry Chinese style: When the class is initialized, the object will be loaded immediately, the thread is inherently safe, and the calling efficiency is high.

Lazy type: When the class is initialized, the object will not be initialized, and the object will be created only when it is really needed, with lazy loading function.

The specific code example is as follows:

1. Hungry Chinese

When the class is initialized, the object will be loaded immediately, the thread is inherently safe, and the calling efficiency is high.

package cn.itchao.singleton;

public class Test01 {

    private final static Test01 test = new Test01();

    private Test01(){

    }

    public static Test01 getInstance(){
        return test;
    }


    public static void main(String[] args) {
        Test01 t1 = Test01.getInstance();
        Test01 t2 = Test01.getInstance();
        System.out.println(t1==t2);
    }
}

2. Lazy-Synchronized Method

package cn.itchao.singleton;

public class Test02 {

    private static Test02 test02;

    private Test02(){

    }

    public static synchronized Test02 getInstance(){
        if(test02==null){
            test02 = new Test02();
        }
        return test02;
    }

    public static void main(String[] args) {
        Test02 t1 = Test02.getInstance();
        Test02 t2 = Test02.getInstance();
        System.out.println(t1==t2);
    }
}

 

3. Lazy Man-Double Check Lock

package cn.itchao.singleton;

public class Test03 {

    private static Test03 test03;

    private Test03(){}

    public static Test03 getInstance(){
        if(test03==null){
            synchronized (Test03.class){
                if(test03==null){
                    test03 = new Test03();
                }
            }
        }
        return test03;
    }

    public static void main(String[] args) {
        Test03 t1 = Test03.getInstance();
        Test03 t2 = Test03.getInstance();
        System.out.println(t1==t2);
    }
}

4. Lazy man--static inner class

package cn.itchao.singleton;

public class Test04 {

    private Test04(){

    }

    static class StaticSingleton{
        private static final Test04  test04 = new Test04();
    }

    public static Test04 getInstance(){
        return StaticSingleton.test04;
    }

    public static void main(String[] args) {
        Test04 t1 = Test04.getInstance();
        Test04 t2 = Test04.getInstance();
        System.out.println(t1==t2);
    }
}

Summarize:

    Advantages: It takes into account the memory optimization of lazy mode (initialized when used) and the security of hungry mode (will not be invaded by reflection).

  Disadvantage: Two classes are required to do this. Although the object of the static inner class will not be created, the Class object will still be created, and it is a permanent object.

5. Hungry Chinese - enumeration

package cn.itchao.singleton;

class Resource{}

enum Singleton{
    INSTANCE;
    private Resource instance;
    Singleton(){
        System.out.println("创建对象");
        instance = new Resource();
    }
    public Resource getInstance(){
        return instance;
    }

}

public class Test05 {
    public static void main(String[] args) {
        Resource t1 = Singleton.INSTANCE.getInstance();
        Resource t2 = Singleton.INSTANCE.getInstance();
        System.out.println(t1==t2);
    }
}

Questions to think about:

1. Choose which way to create a singleton

If you don't need to delay loading singletons, you can use enumeration or hungry Chinese style. Relatively speaking, enumeration is better than hungry Chinese style.

If you need to delay loading, you can use static inner classes or lazy Korean styles. Relatively speaking, static inner classes are better than lazy Korean styles.

2. How to prevent the use of reflection vulnerabilities to attack singletons

In the constructor, only one initialization is allowed.

package cn.itchao.singleton;

import java.lang.reflect.Constructor;

public class Test06 {

    private static volatile boolean flag = false;

    private static Test06 test06 = new Test06();

    private Test06(){
        if(flag == false){
            flag = !flag;
        }else{
            throw new RuntimeException("单例模式被侵犯");
        }
    }


    public static Test06 getInstance(){
        return test06;
    }

    public static void main(String[] args) {
        try {
            Class<?> forName = Class.forName("cn.itchao.singleton.Test06");
            Constructor<?> declaredConstructor = forName.getDeclaredConstructor(null);
            declaredConstructor.setAccessible(true);
            Object s1 = declaredConstructor.newInstance();
            Object s2 = declaredConstructor.newInstance();
            System.out.println(s1==s2);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Results of the:

java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at cn.itchao.singleton.Test06.main(Test06.java:29)
Caused by: java.lang.RuntimeException: 单例模式被侵犯
	at cn.itchao.singleton.Test06.<init>(Test06.java:15)
	... 5 more

Process finished with exit code 0

 

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325185221&siteId=291194637