Design mode (single case mode)

1. Concept

(1) Singleton mode

Adopt a method to ensure that there is only one object instance of a class in the whole software design, and the class only provides a method to obtain its object. Hibernate's SessionFactory is not lightweight. It adopts the singleton mode. Usually, there is only one in a project

(2) Implementation mode

Hungry (static constant), hungry (static code block), lazy (thread unsafe), lazy (thread safe, synchronous method), lazy (thread safe, synchronous code block), double check, static inner class, enumeration

  • Hungry Chinese style can be used, but it is necessary to ensure that the instance will be used, otherwise it will cause a waste of memory
  • Recommended: double check, static inner class and enumeration
  • Lazy style should pay attention to thread safety

(3) Usage scenario

Singleton mode ensures that there is only one object in the system memory, which saves system resources. For some objects that need to be created and destroyed frequently, singleton mode can be used to improve the performance of the system. When you need to instantiate a singleton class, you need to use the method of obtaining the object instead of new

  • Objects that require frequent creation and destruction
  • Objects that take too much time to create or consume too many resources but often need to be used
  • Tool class object
  • Objects that frequently access databases or files (such as data sources, session factories, etc.)

 

2. Hungry man model

(1) Static constant mode

public class Mgr01 {
    private static final Mgr01 INSTANCE = new Mgr01();

    private Mgr01() {};

    public static Mgr01 getInstance() {
        return INSTANCE;
    }

    public static void main(String[] args) {
        Mgr01 m1 = Mgr01.getInstance();
        Mgr01 m2 = Mgr01.getInstance();
        System.out.println(m1 == m2);
    }
}
true

Advantages: the writing method is relatively simple. An object is instantiated after the class is loaded into memory, avoiding the problem of thread synchronization

Disadvantages: it does not achieve the effect of lazy loading. If the object is not used, it will cause a waste of memory

(2) Static code block mode

public class Mgr02 {
    private static final Mgr02 INSTANCE;
    static {
        INSTANCE = new Mgr02();
    }

    private Mgr02() {};

    public static Mgr02 getInstance() {
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        Mgr02 m1 = Mgr02.getInstance();
        Mgr02 m2 = Mgr02.getInstance();
        System.out.println(m1 == m2);
    }
}

Only the code instantiated by the class is placed in the static code block. The advantages and disadvantages are the same as those of static constants

(3) Lazy (thread unsafe)

public class Mgr03 {
    private static Mgr03 INSTANCE;

    private Mgr03() {
    }

    public static Mgr03 getInstance() {
        if (INSTANCE == null) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Mgr03();
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->
                System.out.println(Mgr03.getInstance().hashCode())
            ).start();
        }
    }
}
1850443050
1052444169
2040686731
1919392881
1887032973
1887032973
145632894
145632894
1219201818
1413709757
1413709757
1413709757
1413709757
1413709757

At the beginning, when multiple threads come to the statement to judge whether the object is empty, multiple objects will be generated, that is to say, this method is thread unsafe

(4) Lazy (thread safe, synchronous method)

public class Mgr04 {
    private static Mgr04 INSTANCE;

    private Mgr04() {
    }

    public static synchronized Mgr04 getInstance() {
        if (INSTANCE == null) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Mgr04();
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr04.getInstance().hashCode());
            }).start();
        }
    }
}

Replace the method of obtaining the instance with the synchronous method, but the efficiency will be reduced, and the method will be executed once, and then the object will be returned directly

(5) Reduce the synchronization area, but it is not feasible

public class Mgr05 {
    private static Mgr05 INSTANCE;

    private Mgr05() {
    }

    public static Mgr05 getInstance() {
        if (INSTANCE == null) {
            synchronized (Mgr05.class) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new Mgr05();
            }
        }
        return INSTANCE;
    }
    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr05.getInstance().hashCode());
            }).start();
        }
    }
}

The synchronization method is no longer used to improve the efficiency of the code, but it will bring thread safety problems, because in the case of multithreading, multiple threads will still execute non empty judgment statements

(6) Double check

public class Mgr06 {
    private static volatile Mgr06 INSTANCE; 

    private Mgr06() {
    }

    public static Mgr06 getInstance() {
        if (INSTANCE == null) {
            //duplication check
            synchronized (Mgr06.class) {
                if(INSTANCE == null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Mgr06();
                }
            }
        }
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr06.getInstance().hashCode());
            }).start();
        }
    }
}

Even if multiple threads have crossed the non empty judgment, only the first thread can cross the non empty judgment of the second layer, because the variable modified by volatile can be synchronized back to the main memory immediately after modification, and the second thread is no longer empty when executing

Advantages: lazy loading, high efficiency, thread safety, and only one instance is created

(7) Static inner class

public class Mgr07 {

    private Mgr07() {
    }

    private static class Mgr07Holder {
        private final static Mgr07 INSTANCE = new Mgr07();
    }

    public static Mgr07 getInstance() {
        return Mgr07Holder.INSTANCE;
    }

public static void main(String[] args) { for(int i=0; i<100; i++) { new Thread(()->{ System.out.println(Mgr07.getInstance().hashCode()); }).start(); } } }

According to the static internal class, the internal class will not be loaded when the external class is loaded. Lazy loading is realized. The internal class will be loaded only when the INSTANCE variable is called

And when the internal class is loaded, it is single threaded, which ensures the safety of threads

(8) Enumeration

public enum Mgr08 {

    INSTANCE;

    public void m() {}

    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Mgr08.INSTANCE.hashCode());
            }).start();
        }
    }
}

There is no thread safety problem and can prevent deserialization and re creation of new objects

 

3. Use in JDK

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

 

Posted by ghazianibros on Tue, 19 Apr 2022 03:47:41 +0930