Seven ways to write the singleton pattern

       Reference: http://www.jianshu.com/p/fdc64df67794

     The singleton pattern in Java is a common design pattern. There are many types of singleton patterns. Here are the seven main ones. The singleton pattern has the following characteristics:

       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

  The singleton pattern ensures that there is only one instance of a class, and that it instantiates itself and provides this instance to the entire system. In computer systems, the driver objects of thread pools, caches, log objects, dialog boxes, printers, and graphics cards are often designed as singletons. These applications all have the function of resource manager more or less. Each computer can have several printers, but only one Printer Spooler to avoid two print jobs being output to the printer at the same time. Each computer can have several communication ports, and the system should manage these communication ports centrally to avoid a communication port being called by two requests at the same time. In short, the choice of the singleton mode is to avoid inconsistent states and avoid political bulls.

  The benefits of the singleton pattern: avoid repeated creation of instance objects, reduce the time overhead of creating objects each time, save memory space, and avoid logical errors caused by operating multiple instances;

  

package offer.Singleton;

/**
 * Created by Taoyongpan on 2017/10/9.
 * Implement the singleton pattern
 * Definition: Refers to a class that implements a special mode, the class can only be instantiated once, resulting in a unique object
 * Application example: task manager of windows, recycle bin, configuration object of web application, bean in spring is also a singleton by default
 * Category: hungry, lazy, double-check lock, static inner class, enumeration
 * Evaluation indicators are: singleton (required), thread safety, lazy loading, preventing deserialization from generating new objects, preventing reflection attacks
 * Choice of implementation method: In general, it is good to use the hungry Chinese style directly. When lazy loading is required, static inner classes tend to be used. When it comes to deserialization to create objects or reflection problems, it is best to choose enumeration
 */
public class Singleton {

    public static void main(String[] args){
        Singleton1 singleton1 = Singleton1.getInstance();
        Singleton2 singleton2 = Singleton2.getInstance();
        Singleton3 singleton3 = Singleton3.getInstance();
        Singleton4 singleton4 = Singleton4.getInstance();
        Singleton5 singleton5 = Singleton5.getInstance();
        Singleton6 singleton6 = Singleton6.getInstance();
        Singleton7 singleton7 = Singleton7.instance;
        singleton7.setAttribute("Taoyongpan");
    }

    /**
     * Version 1: Hungry Chinese Style
     * Features: thread safety; resources are allocated when the class is initialized and executed to the static property, and there is a problem of resource waste;
     */
    static class Singleton1{
        private static final Singleton1 instance = new Singleton1();
        //Or make the private static final member a public member, you can omit the getInstance public function
        private Singleton1(){}
        public static Singleton1 getInstance(){
            return instance;
        }
    }

    /**
     * Version 2: Lazy (not thread safe)
     * Features: memory is allocated when the method of obtaining an instance is called for the first time, realizing lazy loading; non-thread-safe;
     */
    static class Singleton2{
        private static Singleton2 instance = null;
        private Singleton2(){}
        public static Singleton2 getInstance(){
            if (instance==null){
                instance = new Singleton2();
            }
            return instance;
        }
    }

    /**
     * Version 3: Lazy variant (synchronized synchronization method, supports multi-threading)
     * Features: thread safety; blocking caused by synchronization leads to low efficiency, and many blocking are unnecessary.
     */
    static class Singleton3{
        private static Singleton3 instance = null;
        private Singleton3(){}
        public static synchronized Singleton3 getInstance(){
            if (instance==null){
                instance = new Singleton3();
            }
            return instance;
        }
    }

    /**
     * Version 4: Lazy variant (synchronized block, supports multithreading)
     * Features: The writing is different, but it has the same problem as version 3
     */

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

    //Version 5: Double check lock DCL, support multi-threading - lazy style
    //Features: Thread safety; make one more if judgment and add volatile modification, the advantage is that it is only locked when it is instantiated for the first time, and it will not be locked after that, which improves the efficiency, but the disadvantage is that the writing method is complicated.
    //If volatile is not added, it may happen that the first if judgment is not null, but the constructor has not been executed, because the java compiler will perform instruction rearrangement;
    //The two major functions of volatile:
    //1 Prevent the compiler from rearranging the instructions of the code related to the modified variable; 2 Read and write operations will not call the working memory but directly fetch the main memory, ensuring memory visibility
    //Instruction rearrangement:
    //instance = new Singleton5() can be divided into three steps: 1 allocate memory, 2 call the constructor, 3 instance points to the allocated memory (instance is not null at this time)
    //The normal order is 123, and the instruction rearrangement may be executed in order of 132, which will cause the problem that it is not null but the constructor is not executed
    // memory visibility:
    //If the field is volatile, the Java memory model will insert a write barrier instruction after the write operation and a read barrier instruction before the read operation.
    //This means: 1. Once the write is done, any thread accessing this field will get the latest; 2. Before writing, any updated data values ​​are visible because the memory barrier will overwrite the previously written value are flushed to the cache.
    //So volatile can provide a certain thread safety, but it is not suitable for the case where the write operation depends on the current value, such as self-increment, self-decrement
    //Simply put, volatile is suitable for this scenario: a variable is shared by multiple threads, and threads directly assign values ​​to this variable.
    //It can also be optimized on the double-check lock and introduce a local variable, but I personally feel that the efficiency commission is not large, so I won't repeat it.
    //volatile reference: http://blog.csdn.net/qq_29923439/article/details/51273812
    static class Singleton5{
        private volatile static Singleton5 instance = null;
        private Singleton5(){}
        public  static Singleton5 getInstance(){
            if(instance==null){
                synchronized (Singleton5.class){
                    if(instance==null)
                        instance = new Singleton5();
                }
            }
            return instance;
        }
    }

    //Version 6: Static inner class, supports multi-threading - lazy style
    //Features: Use static inner classes (only loaded when their references appear) to complete lazy loading; final ensures thread safety;
    //Class loading order: http://blog.csdn.net/u012123160/article/details/53224469
    //The role of final:
    //1. There is no reordering between the writing of a final field within the constructor and the subsequent assignment of a reference to the constructed object to a reference variable.
    //2. The first read of a reference to an object containing a final field, and the subsequent read of the final field, cannot be reordered between the two operations.
    //Extension: static variable initialization follows the following rules:
    //1. Static variables will be declared and set to the default value of the type in the order of declaration, but not assigned to the initialized value.
    //2. After the declaration is completed, set it to the initialized value in the order of declaration. If there is no initialized value, skip it.
    //Static variable initialization reference: http://www.jb51.net/article/86629.htm
    static class Singleton6{
        private Singleton6(){}
        public static Singleton6 getInstance(){
            return Singleton6Holder.instance;
        }
        private static class Singleton6Holder{
            public static final Singleton6 instance = new Singleton6();
        }
    }

    //Version 7: Implemented by enumeration
    //A perfect singleton needs to do: singleton, lazy loading, thread safety, preventing deserialization from generating new objects, preventing reflection attacks
    //And the characteristics of enumeration ensure all the above requirements except lazy loading, and the implementation code is extremely simple
    //Enum's singleton pattern reference: http://www.jianshu.com/p/83f7958b0944
    enum Singleton7{
        instance;
        private String attribute;
        void setAttribute(String attribute){
            this.attribute = attribute;
        }
        String getAttribute(){
            return this.attribute;
        }
    }

}

 

  

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326712454&siteId=291194637