There are thousands of design patterns, and singletons are always the most common.

Definition of a singleton pattern

Ensure that a class has only one instance and provide a global access point to access it.

Six ways to create a singleton

1. The hungry

public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; }}Copy the code

Advantages: Class-based loading mechanism, avoiding multi-thread synchronization, fast loading.

Disadvantages: initialization is done at class load time, no lazy loading, and memory is wasted if the instance is not used.

2. Slacker – Thread Unsafe edition

public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if(instance == null){ instance = new Singleton(); } return instance; }}Copy the code

Advantages: The object is initialized only on the first call, avoiding wasting resources

Disadvantages: Slow loading and thread insecurity

3. Synchronized synchronized

public class Singleton { private static Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if(instance == null){ instance = new Singleton(); } return instance; }}Copy the code

Advantages: Ensure thread safety in multi-threading Disadvantages: Each object instance needs to be synchronized, resulting in unnecessary synchronization overhead.

4. Double check lock

public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if(instance == null){ synchronized(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; }}Copy the code

Advantages: Thread-safe, lazy loading, reduced synchronization overhead

Disadvantages: The first object acquisition is a bit slow, but it fails in some cases and is not perfect.

Nulling is used twice: the first time for unnecessary lock synchronization, and the second time to ensure that instances are created only when instance is null to avoid multiple instances.

Volatile = volatile; volatile = volatile; volatile = volatile;

1. Volatile guarantees visibility and prevents reordering of program instructions in the Java memory model.

2. Object creation is divided into the following steps:

Instance = new Singleton ();Copy the code
  • 1. Allocate memory space for instance
  • 2. Initialize instance
  • 3. Point instance to the memory address

Without volatile, the order of execution could be 1->3->2, causing threads to acquire an uninitialized instance. For example, thread a does 1,3, and thread b calls getInstance() to find instance not empty and returns instance, but instance has not been initialized yet.

5. Static inner classes

public class Singleton { private Singleton() {} public static Singleton getInstance() { return SingletonHolder.sInstance; } private static class SingletonHolder { private static final Singleton sInstance = new Singleton(); }}Copy the code

Instance is not initialized when the class is loaded for the first time. Instance is loaded and initialized only when getInstance() is called for the first time. This ensures thread-safe and unique instances.

6. The enumeration

public enum Singleton {
INSTANCE;
public void doSomeThing(){}
}
Copy the code

The default enumeration singleton is created thread-safe and is a singleton in any case.

These are the common forms of singleton creation in 6, so use them on demand.

Usage scenarios of singletons

  • The entire project requires a shared access point or data
  • Creating an object requires too many resources, such as accessing database resources
  • Utility class object