Design Patterns - Singleton Pattern (Singleton)

Design Patterns (1) - Singleton Pattern (Singleton)

The simplest design pattern, this pattern involves a single class that 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 object, directly, without instantiating an object of the class. This class can only new out of one object.

  • advantage:
  1. There is only one instance in memory, which reduces memory overhead, especially when instances are created and destroyed frequently (such as the cache of the home page of the School of Management).
  2. Avoid multiple occupation of resources (such as write file operations).
  • Disadvantages: No interface, no inheritance, conflicts with the principle of single responsibility, a class should only care about the internal logic, not how to instantiate it outside.

how to create

Hungry Chinese

I think it is the simplest way to write, and the shortcomings are not prominent.
Create a static object in the class and use public methods to access the object.

  • Advantages: There is no lock, and the execution efficiency will be improved. thread safe.
  • Disadvantages: The class is initialized when the class is loaded, which wastes memory.
//Hungry Chinese
public class Mgr {
    //Create a singleton object
    private static final Mgr mgr = new Mgr();
    //constructor private
    private Mgr() {
    }
    //Access objects through public methods
    public static Mgr GetMgr() {
        return mgr;
    }

    public static void main(String[] args) {
        //Create a singleton object
        Mgr mgr = Mgr.GetMgr();
    }
}
lazy

thread unsafe
Determine whether the object is instantiated when it is instantiated,
If not, create the object,
If there is, return the object

/*
lazy
 Determine whether the object is instantiated when it is instantiated,
If not, create the object,
If there is, return the object
 */
public class Mgr {
    //The final keyword cannot be used here, otherwise it cannot be changed
    public static Mgr mgr = null;
    private Mgr() {
    }

    //Check if mgr is empty
    public static Mgr getMgr() {
        if(mgr==null) {
            mgr = new Mgr();
            return mgr;
        }
        else return mgr;
    }

    public static void main(String[] args) {
        //Create a singleton object
        Mgr mgr = Mgr.getMgr();
    }
}

But this way of writing is not safe. When using multi-threading, if(mgr==null) is executed, and the object has not been created, another thread also executes if(mgr==null), so it leads to the creation of multiple objects.

import static java.lang.Thread.sleep;
/*
lazy
 Determine whether the object is instantiated when it is called,
If not, create the object,
If there is, return the object
 */
public class Mgr {
    //The final keyword cannot be used here, otherwise it cannot be changed
    public static Mgr mgr = null;
    private Mgr() {
    }

    //Check if mgr is empty
    public static Mgr getMgr() {
        if(mgr==null) {
            //There is an operation delay here for a fraction of the time 1
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mgr = new Mgr();
            return mgr;
        }
        else return mgr;
    }

    public static void main(String[] args) {
        //Create a singleton object from multiple threads
        for(int i=1; i<100; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                    Mgr mgr = Mgr.getMgr();
                    System.out.println(mgr);

            }
        }).start();}

    }
}

It can be seen that not all of the output addresses are consistent.

Lazy (locked)

Solve lazy thread-safety issues
Lock before getMgr() to make it a synchronized method

import static java.lang.Thread.sleep;

/*
lazy
 Determine whether the object is instantiated when it is called,
If not, create the object,
If there is, return the object
 */
public class Mgr {
    public static Mgr mgr = null;
    private Mgr() {
    }

    //Check if mgr is empty
    public static synchronized Mgr getMgr() {
        if(mgr==null) {
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mgr = new Mgr();
            return mgr;
        }
        else return mgr;
    }

    public static void main(String[] args) {
        //Create a singleton object from multiple threads
        for(int i=1; i<100; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                    Mgr mgr = Mgr.getMgr();
                    System.out.println(mgr);

            }
        }).start();}

    }
}

double lock

The efficiency of the synchronization method is too low, so there is a way to add double locks.
The two judgments here are necessary, because there may be multiple threads passing the first layer judgment.

import static java.lang.Thread.sleep;

/*
lazy
 Determine whether the object is instantiated when it is called,
If not, create the object,
If there is, return the object
 */
public class Mgr {
    public static Mgr mgr = null;
    private Mgr() {
    }

    //Check if mgr is empty
    public static  Mgr getMgr() {
        if(mgr==null) {
            synchronized (Mgr.class) {   //double lock
                if(mgr==null) {
                    synchronized (Mgr.class) { //double lock
                        try {
                            sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        mgr = new Mgr();
                    }
                }

            }

            return mgr;
        }
        else return mgr;
    }

    public static void main(String[] args) {
        //Create a singleton object from multiple threads
        for(int i=1; i<100; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {

                    Mgr mgr = Mgr.getMgr();
                    System.out.println(mgr);

            }
        }).start();}

    }
}
static inner class

This method does not produce garbage objects and does not produce thread safety.
JVM guarantees: static classes are loaded only once. And the inner class is not loaded when the outer class is loaded.

public class Mgr {
    private Mgr() {
    }
    private static class MgrHolder {
        private static final Mgr mgr = new Mgr();
    }
    //Check if mgr is empty
    public static  Mgr getMgr() {
       return MgrHolder.mgr;
    }

    public static void main(String[] args) {
       Mgr mgr = Mgr.getMgr();
    }
}
enumeration singleton

Can prevent deserialization

public enum Mgr{
    mgr;
}

Tags: Java Design Pattern Singleton pattern

Posted by flyersman on Fri, 21 Oct 2022 22:04:32 +0530