Java Singleton Pattern Creation Destroy and Anti Destroy Detailed Explanation

  • 2021-11-10 09:36:25
  • OfStack

Directory Preface Singleton Mode Several implementations of singleton mode are lazy, thread unsafe lazy, thread safe hungry double check lock/double check lock registration/static internal class enumeration. Anti-destruction summary of singleton mode

Preface

The well-known singleton pattern can only create only 11 instances. Today, we introduce several common singleton patterns, and at the same time, we will talk about how to destroy singleton patterns and how to prevent them from being destroyed.

Singleton pattern

The singleton pattern (Singleton Pattern) is one of the simplest design patterns in Java. This type of design pattern belongs to the Creative Pattern and provides one of the best ways to create objects.

This pattern involves a single 1 class, which is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its only 1 object, which can be accessed directly without instantiating the object of this class.

1. A singleton class can have only one instance.

2. Singleton classes must create their own only 1 instances.

3. The singleton class must provide this 1 instance to all other objects.

Several implementations of singleton pattern

Lazy, thread unsafe

The following lazy mode is thread-unsafe and supports lazy loading. Because synchronized is not locked, it is not strictly singleton mode.

Sample code:


public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}

Lazy, thread-safe

The following method can ensure thread safety and support lazy loading. The advantage is that it is initialized only after the first call, thus avoiding memory waste. The disadvantage is that synchronized must be locked to ensure singleton, but locking will affect efficiency.

Sample code:


public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static synchronized Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}

Hungry Han style

Hungry Han type, more commonly used, but easy to participate in garbage objects, this way does not support lazy loading, thread safety, the advantage is that there is no lock, and the execution efficiency will be improved. The disadvantage is that the class is initialized when it is loaded, which wastes memory.

Sample code:


public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){
    }  
    public static Singleton getInstance() {  
    	return instance;  
    }  
}

Double check lock/double check lock

This method supports lazy loading and thread safety. This method adopts double lock mechanism, which is safe and can maintain high performance in multithreaded situations.

Sample code:


public class Singleton {  
    private volatile static Singleton instance;
    private Singleton(){
    }
    public static Singleton getInstance(){
        if(instance==null){
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    } 
}

Registrar/static inner class

This method supports lazy loading and thread safety. This method can achieve the effect of double-check lock mode 1, but it is simpler to implement. Use delayed initialization for static domains, which should be used instead of double-check locking. This method is only suitable for static domains, and the double-check lock method can be used when the instance domain needs delayed initialization.


public class Singleton {  
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private  Singleton(){
    }
    public static final Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }  
}

Enumerate

This implementation does not support lazy loading, is thread-safe, and is not yet widely adopted, but is the best way to implement the singleton pattern. It is simpler, automatically supports serialization mechanism, and absolutely prevents multiple instantiations. This approach, advocated by Effective Java author Josh Bloch, not only avoids the problem of multithreaded synchronization, but also automatically supports serialization mechanisms, preventing deserialization from recreating new objects and absolutely preventing multiple instantiations.


public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

Simulate a database connection class:


public enum SingletonEnum {
    INSTANCE;
    private DBConnection connection = null;
    SingletonEnum(){
        connection = new DBConnection();
    }
    public DBConnection getConnection(){
        return connection;
    }
}

public class DBConnection{
}

public class TestConnection {
    public static void main(String[] args) {
        DBConnection con1 = DataSourceEnum.DATASOURCE.getConnection();
        DBConnection con2 = DataSourceEnum.DATASOURCE.getConnection();
        System.out.println(con1 == con2); // The output is true . 
    }
}

Break the singleton pattern

There are two main ways to break the singleton pattern: reflection and deserialization

We will take the most classic hungry Han style to demonstrate destruction and destruction prevention.

Undamaged condition

Singleton:


/**
 * Keafmd
 *
 * @ClassName: Singleton
 * @Description:  Singleton pattern 
 * @author:  Conan, who is full of cattle 
 * @date: 2021-09-07 10:53
 */
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){
    }
    public static Singleton getInstance() {
        return instance;
    }
}

Test class (undamaged):


public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static synchronized Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}
0

The situation after the damage

Singleton: (unchanged)


public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static synchronized Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}
1

Test class (broken by reflection):


public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static synchronized Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}
2

Output:

com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
true
com.keafmd.Study.designPatterns.Blog.Singleton@511d50c0
com.keafmd.Study.designPatterns.Blog.Singleton@60e53b93
false

Process finished with exit code 0

This kind of destruction is to create an instance through the reflection mechanism of java. This kind of destruction method is to skip the detection syntax of java through the method of setAccessible (true), which can temporarily change the access authority and obtain the private member variable.

Anti-corruption of singleton pattern

In fact, the simplest way to prevent damage is to judge whether an instance has been created. If it is the second time to create an instance object, throw an exception directly to prevent the creation.

Override the Singleton class:


package com.keafmd.Study.designPatterns.Blog;
/**
 * Keafmd
 *
 * @ClassName: Singleton
 * @Description:  Singleton pattern 
 * @author:  Conan, who is full of cattle 
 * @date: 2021-09-07 10:53
 */
public class Singleton {
    // Prevent instantiation 
    private static boolean flag=true;
    private static Singleton instance = new Singleton();
    private Singleton (){
        if(!flag){
            throw new RuntimeException(" This singleton schema class cannot create more objects ");
        }
    }
    public static Singleton getInstance() {
        if(flag){
            flag=false; // No. 1 1 It changes when it is created next time flag The value of, causing the subsequent creation to be unsuccessful 
        }
        return instance;
    }
}

Test class (unchanged):


public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static synchronized Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}
4

Output:

com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
true
Exception in thread "main" 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 com.keafmd.Study.designPatterns.Blog.SingletonTest.main(SingletonTest.java:28)
Caused by: java. lang. RuntimeException: This singleton schema class cannot create any more objects
at com.keafmd.Study.designPatterns.Blog.Singleton. < init > (Singleton.java:28)
... 5 more

Process finished with exit code 1

Thus, when executing to Singleton instance22 = constructor. newInstance (); In this line, an exception will be thrown, thus preventing damage.

Summarize

This article is here, I hope to give you help, but also hope that you can pay more attention to this site more content!


Related articles: