Java Foundation Series - Seven Ways to Write Singletons

Keywords: Java

Original articles, reprinted please indicate the source: Java Foundation Series - Seven Ways to Write Singletons

I. overview

There are seven ways to write singletons in Java, which are often asked in interviews, and sometimes require handwritten singletons to be implemented. So it is necessary for us to understand these seven ways of writing carefully.

II. Seven Realizations

2.1 Lazy-Thread Insecurity

public class SingletonOne {
    public static SingletonOne singleton;
    private SingletonOne() {}
    public static SingletonOne getSingleton() {
        if (singleton == null)
            return new SingletonOne();
        return singleton;
    }
}

Lazy Load is implemented in Lazy Load mode, but the thread is not safe and will not be used at all.

2.2 Slacker-Thread Safety

public class SingletonTwo {
    public static SingletonTwo singleton;
    private SingletonTwo() {}
    public static synchronized SingletonTwo getSingleton() {
        if (singleton == null)
            return new SingletonTwo();
        return singleton;
    }
}

On the basis of the first one, a synchronized thread is added to ensure thread safety, while lazy loading is realized, but the efficiency is not high.

2.3 Hungry Chinese Style

public class SingletonThree {
    public static SingletonThree singleton = new SingletonThree();
    private SingletonThree () { }
    public static SingletonThree getSingleton() {
        return singleton;
    }
}

Because instances are provided first, there is no thread security problem, but lazy loading is not implemented.

2.4 Hungry Chinese Style-Variety

public class SingletonFour {
    public static SingletonFour singleton;
    static {
        singleton = new SingletonFour();
    }
    private SingletonFour () { }
    public static SingletonFour getSingleton() {
        return singleton;
    }
}

In fact, as before, it just moved the creation of singletons to static blocks.

2.5 Static Internal Classification

public class SingletonFive {
    private static class SingletonHolder {
        private static SingletonFive singleton = new SingletonFive();
    }
    private SingletonFive () {}
    public static final SingletonFive getSingleton(){
        return SingletonHolder.singleton;
    }
}

Static inner class ensures lazy loading, and single instance priority ensures thread security, which is more practical.

2.6 Enumeration Formula

public enum SingletonSix {
    SINGLETON;
}

The natural features of enumeration ensure the security of singletons, natural private constructors, and natural threads. The reason why enumeration is not widely used is that enumeration appears a little late.

2.7 Double Check Lock

public class SingletonSeven {
    private static volatile SingletonSeven singleton;
    private SingletonSeven() {}
    public static SingletonSeven getSingleton(){
        if (singleton == null) {
            synchronized (SingletonSeven.class) {
                if (singleton == null)
                    return new SingletonSeven();

            }
        }
        return singleton;
    }
}

Be careful:

  1. The use of volatile to prevent the exposure of an uninitialized incomplete singleton instance;
  2. Double empty check, the first judgment avoids frequent locking, and the second judgment can block the redundant thread of creating instances.
  3. Locking ensures thread safety (only one instance)

This way of implementation often appears in the interview questions, and often requires handwriting.

Three, summary

Among the seven design patterns listed above, the first thread is unsafe and can be excluded, while the third and fourth are actually one, which can be simplified into five ways: lazy, hungry, static inner classes, enumeration, double check locks.

Posted by perpetualshaun on Thu, 09 May 2019 11:54:39 -0700