Java singleton design pattern

Posted by shainh on Wed, 08 Dec 2021 09:21:07 +0100

What is the singleton design pattern

In the whole system, there is only one instance object of a class that can be obtained and used

main points

  • A class can only have one instance object

    Constructor privatization

  • You must create this instance yourself

    Contains a static variable of this class to store this instance

  • Provide this instance to the entire system

    Provide external access to the instance

Single case design pattern classification

Single case design patterns are divided into two categories: lazy and hungry

Hungry man style: as the name suggests, I'm very hungry now. I see a bread and I'm going to eat it right away. So when the whole system is loaded, whether you use it or not, you can create it directly.

Lazy style: also very understandable. I'm very lazy and have serious procrastination. I don't do it when I have to. That is, I create this object only when I need to use it.

Hungry Chinese implementation

Because this object is created when the system loads, starving is thread safe. There are three ways to achieve hungry Han style.

Direct instantiation hungry Chinese style (concise and intuitive)

public class Singleton1 {
    //2. Store the instance with a static object
    public static final Singleton1 INSTANCE = new Singleton1();
    //1. Privatization of constructor
    private Singleton1(){

    }
}

Enumeration method (the most convenient)

public enum Singleton2 {
    INSTANCE
}

Static code block

In fact, the effect is the same, but static code blocks are more suitable for setting complex parameters during initialization

If we want to read parameters from an external configuration file when we create a parameterized construction method, we can use static code blocks to create it

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

Lazy implementation

Thread unsafe (for single thread)

public class Singleton4 {
    //2. Store the instance with a static object
    private static Singleton4 INSTANCE;
    //1. Privatization of constructor
    private Singleton4(){

    }
    //3. Expose examples through methods
    public static Singleton4 getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Singleton4();
        }
        return INSTANCE;
    }
}

You can test thread insecurity by

public class Singletontest4 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Singleton4> c = new Callable<Singleton4>() {
            @Override
            public Singleton4 call() throws Exception {
                Singleton4 s = Singleton4.getInstance();
                return s;
            }
        };

        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Singleton4> submit1 = es.submit(c);
        Future<Singleton4> submit2 = es.submit(c);
        Singleton4 s1 = submit1.get();
        Singleton4 s2 = submit2.get();
        System.out.println(s1);
        System.out.println(s2);
    }
}

Thread safe (for multithreading)

Thread security is nothing more than adding a lock

public class Singleton5 {
    //2. Store the instance with a static object
    private static Singleton5 INSTANCE;
    //1. Privatization of constructor
    private Singleton5(){

    }
    //3. Expose examples through methods
    public static Singleton5 getInstance(){
        if(INSTANCE == null){
            synchronized (Singleton5.class) {
                INSTANCE = new Singleton5();
            }
        }
        return INSTANCE;
    }
}

Static internal class form (applicable to multithreading)

Calling the initialization method into a static internal class is absolutely thread safe.

public class Singleton6 {
    private Singleton6(){

    }

    private static class Inner{
        private static final Singleton6 INSTANCE = new Singleton6();
    }

    public static Singleton6 getInstance(){
        return Inner.INSTANCE;
    }
}

Topics: Java Singleton pattern