The singleton pattern

  • The hungry mode
public class Hungry { private Hungry() {} public static Hungry instance = new Hungry(); public static Hungry getInstance() { return instance; }}Copy the code

The reason why it is called hungry mode is because when you are hungry, you can create a new object and it doesn’t work, so you don’t have the advantages of lazy loading. Thread safety, high call efficiency

  • Optimise the hunchman mode so that soon new objects will be created, and new objects will be created when needed
public class Lazy { private Lazy(){ } public static Lazy instance; public static Lazy getInstance(){ if (instance == null) { instance = new Lazy(); } return instance; }}Copy the code

This way, it’s fine in the single-threaded case, but in the multi-threaded case, it’s possible that you’re not returning the same object.

  • To optimize for multithreading, add the sychornized keyword to getInstance
public class Lazy { private Lazy(){ } public static Lazy instance; public static synchronized Lazy getInstance(){ if (instance == null) { instance = new Lazy(); } return instance; }}Copy the code
  • Support multithreading, but not high efficiency, only one thread at a time, other threads wait, and then optimize,instance == null and then lock
public class Lazy { private Lazy(){ } public static Lazy instance; Public static Lazy getInstance(){if (instance == null) {// If (instance == null) { Synchronized (lazy.class){instance = new Lazy(); synchronized (lazy.class){instance = new Lazy(); } } return instance; }}Copy the code
  • If both A and B arrive at the same place,A finishes,instance! = null The object is new again. If you need to optimize it further, you can use a double-layer check, which checks for two instances == NULL
public class Lazy { private Lazy(){ } public static Lazy instance; public static Lazy getInstance(){ if (instance == null) { synchronized (Lazy.class){ if (instance == null) { instance = new Lazy(); } } } return instance; }}Copy the code
  • Is that all right now? Instance = new Singleton(), which is not an atomic operation, actually does three things in the JVM.
1. Allocate memory for instance 2. Call Singleton's constructor to initialize member variables 3. Reference instance to the allocated memory space (instance is not null after this step)Copy the code

But there is an optimization for instruction reordering in the JVM’s just-in-time compiler. That is to say, the order of step 2 and step 3 above is not guaranteed, and the final execution order may be 1-2-3 or 1-3-2. If it is the latter, instance is preempted by thread 2 before instance 3 is executed and instance 2 is already non-null (but not initialized), so thread 2 returns instance directly, uses it, and then naturally reports an error

The solution is simply to declare the instance variable volatile

  • Check out the final version of Slacker mode
public class Lazy { private Lazy(){ } public static volatile Lazy instance; public static Lazy getInstance(){ if (instance == null) { synchronized (Lazy.class){ if (instance == null) { instance = new Lazy(); } } } return instance; }}Copy the code
  • Static inner class
public class StaticInnerClass { private StaticInnerClass() { } private static class InnerHolder { private static final StaticInnerClass instance = new StaticInnerClass(); } public static StaticInnerClass getInstance() { return InnerHolder.instance; }}Copy the code

Thread safety, lazy loading, recommended

  • Enumeration singleton. This method is recommended
Public class SingletonExample7 {private SingletonExample7() {} public static SingletonExample7 getInstance() { return Singleton.INSTANCE.getInstance(); } private enum Singleton { INSTANCE; private SingletonExample7 singleton; Singleton() {Singleton = new SingletonExample7(); Singleton = new SingletonExample7(); } public SingletonExample7 getInstance() { return singleton; }}}Copy the code

Enumerations are the best way to implement singletons, thread-safe (JVM internal implementation, we don’t need to lock any more), lazy loading, and preventing reflection and deserialization from breaking singletons