Example of Creator mode (with code explanation)

There are three categories in the design pattern according to different processing methods; Creative mode, structural mode and behavior mode, of which four have been introduced; Factory method pattern, abstract factory pattern, generation pattern and prototype pattern, in addition to the last example pattern.

In the preparation of the re learning Java design pattern, use various scenarios as much as possible, and also introduce the use of the design, including the scenarios we have used; Various types of prizes are distributed, multiple sets of Redis cache clusters are upgraded, the quotation list of decoration companies and hundreds of test questions and answers are out of order, and the idea of design mode is felt through the practice of these scenarios. However, these scenes are separated by the author through experience, not the knowledge of the reader, so if you want to master them thoroughly, you must operate them personally and complete them personally.

I still want to emphasize the learning methods here. There are always many children who have doubts about learning knowledge. They clearly understand it when they read it, but they can't use it when they actually use it. Or sometimes I think it would be better if there were no more vivid cartoons or comparisons. Of course, these methods may speed up a newcomer's understanding of knowledge. But as long as you watch learning videos as movies and learning books as stories, it is difficult to master this technology stack. Only when you use it, dig word by word, explore a little, and clear all the blind spots you encounter, can you really master this skill.

1, Development environment

1. JDK 1.8

2. Idea + Maven

2, Introduction to singleton mode

Example mode is one of the simplest modes in the whole design, and this method will be often used in coding development even without looking at the relevant data of design mode.

This is because we often encounter such a scenario in programming development, that is, we need to ensure that a class has only one instance, even if multiple threads access it at the same time, and we need to provide a global access point to this instance.

To sum up, as well as our usual development, we can sum up an experience. The single example mode mainly solves the frequent creation and consumption of a globally used class, so as to improve the performance of the overall code.

3, Case scenario simulation

The scene of the technology in this chapter is very simple, which can be seen in our daily development, for example;

1. The database connection pool will not be created repeatedly

2. Generation and use of a single example pattern bean in spring

3. In our normal code, we need to set some global properties to save

In our daily development, the single example mode is generally used in the above scenarios. Although the single example mode is not complex, it is widely used.

4, Implementation of 7 single example modes

There are many implementation methods of single example mode, mainly whether to support lazy mode and whether to use various skills in thread safety. Of course, there are some scenarios that do not need to consider lazy loading, that is, lazy mode. They will be handled directly by using static static classes or properties and methods for external calls.

Then we will explain the example mode by implementing different ways.

0. Use of static classes

public class Singleton_00 {

    public static Map<String,String> cache = new ConcurrentHashMap<String, String>();

}

The above methods are very common in our normal business development. In this way, the static class method can directly initialize the Map class when it is run for the first time. At the same time, we don't need to delay loading.

It is only used for global access without maintaining any state. This way of using static classes is more convenient.

However, if you need to be inherited and maintain some specific states, it is suitable to use the example mode.

1. Lazy mode (thread unsafe)

public class Singleton_01 {

    private static Singleton_01 instance;

    private Singleton_01() {
    }

    public static Singleton_01 getInstance(){
        if (null != instance) return instance;
        return new Singleton_01();
    }

}

One feature of the example mode is that it does not allow external direct creation, that is, new Singleton_01(), so this adds the private attribute private to the default constructor.

At present, the examples in this way do meet the lazy loading, but if multiple visitors go to obtain the object examples at the same time, you can imagine that a group of people are robbing the toilet, multiple identical examples will coexist, thus failing to meet the requirements of the examples.

2. Lazy mode (thread safety)

public class Singleton_02 {

    private static Singleton_02 instance;

    private Singleton_02() {
    }

    public static synchronized Singleton_02 getInstance(){
        if (null != instance) return instance;
        return new Singleton_02();
    }

}

Although this mode is secure, all accesses need to be locked after the lock is added to the method, resulting in a waste of resources. If it is not a special case, it is not recommended to implement the example mode in this way.

3. Hungry Han mode (thread safe)

public class Singleton_03 {

    private static Singleton_03 instance = new Singleton_03();

    private Singleton_03() {
    }

    public static Singleton_03 getInstance() {
        return instance;
    }

}

This method is basically the same as the first example Map at the beginning. It is loaded directly when the program is started, and can be obtained when external needs to be used later.

But this method is not lazy loading, that is, whether you use such a class in your program or not, it will be created at the beginning of the program.

The problem caused by this method is like downloading a game software. Maybe your game map has not been opened, but the program has instantiated all these maps. The most obvious experience on your mobile phone is that as soon as you open the game, the memory is full, the mobile phone card is out and needs to be replaced.

4. Use the inner class of the class (thread safety)

public class Singleton_04 {

    private static class SingletonHolder {
        private static Singleton_04 instance = new Singleton_04();
    }

    private Singleton_04() {
    }

    public static Singleton_04 getInstance() {
        return SingletonHolder.instance;
    }

}

The single example mode implemented by using the static internal class of the class not only ensures thread safety, but also ensures lazy loading, and will not consume performance because of the locking method.

This is mainly because the JVM virtual machine can ensure the correctness of multi-threaded concurrent access, that is, the construction method of a class can be loaded correctly in a multi-threaded environment.

This method is also a highly recommended example mode

5. Double lock verification (thread safety)

public class Singleton_05 {

    private static volatile Singleton_05 instance;

    private Singleton_05() {
    }

    public static Singleton_05 getInstance(){
       if(null != instance) {
           return instance;
       }
       synchronized (Singleton_05.class){
           if (null == instance){
               instance = new Singleton_05();
           }
       }
       return instance;
    }

}

The method of double locking is the optimization of method level locking, which reduces the time-consuming of obtaining some examples.

At the same time, this method also meets the lazy loading.

6. CAS "AtomicReference" (thread safety)

public class Singleton_06 {

    private static final AtomicReference<Singleton_06> INSTANCE = new AtomicReference<Singleton_06>();

    private static Singleton_06 instance;

    private Singleton_06() {
    }

    public static final Singleton_06 getInstance() {
        for (; ; ) {
            Singleton_06 instance = INSTANCE.get();
            if (null != instance) return instance;
            INSTANCE.compareAndSet(null, new Singleton_06());
            return INSTANCE.get();
        }
    }

    public static void main(String[] args) {
        System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d
        System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d
    }


}

java concurrency library provides many atomic classes to support the data security of concurrent access; AtomicInteger , AtomicBoolean , AtomicLong , AtomicReference . Atomicreference can encapsulate and reference a V example and support concurrent access. The above example uses this feature.

The advantage of using CAS is that it does not need to use the traditional locking method to ensure thread safety, but depends on the busy algorithm of CAS and the implementation of underlying hardware to ensure thread safety. Compared with other lock implementations, there is no thread switching and blocking, so there is no additional overhead, and it can support large concurrency.

Of course, CAS also has a disadvantage that it is busy. If it has not been obtained, it will be in an endless loop

7. Enumeration examples recommended by effective Java authors (thread safety)

public enum Singleton_07 {

    INSTANCE;
    public void test(){
        System.out.println("hi~");
    }

}

The author of Effective Java recommends using enumeration to solve the single example mode, which may be the least used at ordinary times.

This method solves the most important problems; Thread safety, free implementation, single example.

Adjustment mode

public class ApiTest {

    @Test
    public void test() {
        Singleton_07.INSTANCE.test();
    }

}

This method is similar to the common domain method in function, but it is more concise and provides an implementation mechanism free of charge to absolutely prevent it from being instantiated, even in the face of complex implementation or reflection attacks. Although this method has not been widely used, the enumeration type of single element has become the best method to implement Singleton. However, you should also know that this method is not available in the presence of inheritance scenarios.

5, Summary

Although it is only a very common single example mode, we can really see the embodiment of the basic skills of java in various implementations, including; Lazy, hungry, thread safety, static class, internal class, locking, execution, etc

In normal development, if you can ensure that this class is globally available without lazy loading, you can directly create it and call it externally. However, if there are many classes that need to be displayed after the user triggers certain conditions (game levels), you must use lazy loading. Thread security can be selected on demand.

Tags: Java Design Pattern

Posted on Wed, 29 Sep 2021 20:38:02 -0400 by Rabea