We have collected various implementation methods of singleton.

Singleton implementation type

Typical

The most typical way to write it is Non Thread Safe.

public class Singleton1 {
    private static Singleton1 singleton = null;

    private Singleton1() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton1 getInstance() {
        if (singleton == null) {
            singleton = new Singleton1();
        }
        return singleton;
    }
}

Non-Thread-Safe


ExecutorService executor = Executors.newFixedThreadPool(2);

Future<Singleton1> f1 = executor.submit(Singleton1::getInstance);
Future<Singleton1> f2 = executor.submit(Singleton1::getInstance);

Singleton1 s1 = f1.get();
Singleton1 s2 = f2.get();

System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);

Different ID


design.singleton.Singleton1@7ba4f24f
design.singleton.Singleton1@3b9a45b3
false

synchronized Add synchronized to the typical writing style to make it Thread Safe. However, there is a performance concern because the synchronized lock cannot be released even after the instance is created.

synchronized


public class Singleton2 {
    private static Singleton2 singleton = null;

    private Singleton2() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static synchronized Singleton2 getInstance() {
        if (singleton == null) {
            singleton = new Singleton2();
        }
        return singleton;
    }
}

Double Check Lock By adding Check again on top of synchronized, It avoids the synchronized lock.

But it's not actually Thread Safe due to atomicity issues! I don't know the details, but it is because new Singleton3 () is broken down into several parts and executed.

DCL


public class Singleton3 {
    private static Singleton3 singleton = null;

    private Singleton3() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton3 getInstance() {
        //Not thread-safe due to atomicity
        if (singleton == null) {
            synchronized (Singleton3.class) {
                if (singleton == null) {
                    singleton = new Singleton3();
                }
            }
        }
        return singleton;
    }
}

volatile + DCL It uses volatile, guarantees primitiveness, and implements Double Check Lock.

volatile


public class Singleton4 {
    private static volatile Singleton4 singleton = null;

    private Singleton4() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton4 getInstance() {
        //Volatile guarantees atomicity
        if (singleton == null) {
            synchronized (Singleton4.class) {
                if (singleton == null) {
                    singleton = new Singleton4();
                }
            }
        }

        return singleton;
    }
}

static fianl Thanks to the class loader, it is Thread Safe and simple to write. However, resources can be wasted.

static_final


public class Singleton5 {

    private static final Singleton5 singleton = new Singleton5();

    private Singleton5() {}

    public static Singleton5 getInstance() {
        return singleton;
    }
}

Holder It is an implementation that makes Thread Safe with static final, but does not waste resources by generating delays.

Holder


public class Singleton6 {

    private static class SingletonHolder {
        private static final Singleton6 singleton = new Singleton6();
        private SingletonHolder() { }
    }

    private Singleton6() {
    }

    public static Singleton6 getInstance() {
        return SingletonHolder.singleton;
    }
}

enum Use enum. However, resources can be wasted.

enum


public enum Singleton7 {
    SINGLETON;
}

The essence is not much different from static final, but it is public. public static final Singleton7 SINGLETON = new Singleton7();

Summary

Implementation method Wasted resources Thread safety Thread performance considerations
Typical NO NO -
synchronized NO YES NO
Double Check Lock NO NO -
volatile + DCL NO YES YES
static fianl YES YES YES
Holder NO YES YES
enum YES YES YES

Overall, volatile + DCL or Holder is the best!

Recommended Posts

We have collected various implementation methods of singleton.
Various methods of Java String class
Various methods of the String class
Implementation of delete function (if you have foreign_key)
We have extracted the best plastics of Dockerfile!
Implementation of GKAccessPoint