The singleton pattern
Singleton: A creative design pattern, it is arguably one of the most used and simplest design patterns. Its purpose is to ensure that there is only a single instance object for a class in the entire software system, and that the class provides only one way to access its unique objects (usually static methods), which can be accessed directly without instantiating the objects of the class. In plain English, the entire software system is built, the entire class, instantiated an object, and provides a unique access to the external, to ensure that in the entire system, only a single instance of the object, other classes to access it, just call the use of it, no need to instantiate it.
Here are eight ways to write a singleton pattern:
① Hungry (static constant)
public class Singleton {
//1. Privatize the constructor
private Singleton(a) {}//2. Create an object instance inside the class
private final static Singleton instance = new Singleton();
//3. Expose a static public method that can be called externally, return the instance object
public static Singleton getInstance(a){
returninstance; }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); }}Copy the code
Running results:
The advantages and disadvantages
- Advantages: Simple and rough writing, avoid thread synchronization problems
- Disadvantages: Instantiation is done when the class is loaded, not lazy loading.
- why: This method is based on
Classloder
The mechanism avoids multithreaded synchronization issues, but at the same time singletons are instantiated as soon as the class is loaded, resulting in a waste of memory if the instance is never used. There are many reasons for class loading, and while most singletons call getInstance, there is no guarantee that there are no other ways or static methods that can cause class loading, so this singletons are not lazy loading. - Summary: This method works, but it may be a waste of memory
② Hungry (static code block)
public class Singleton {
//1. Privatize the constructor
private Singleton(a) {}//2. Create an object instance inside the class
private static Singleton instance;
static {//3. Create a singleton in a static code block
instance = new Singleton();
}
//4. Expose a static public method that can be called externally, return the instance object
public static Singleton getInstance(a){
returninstance; }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
System.out.println("-- Hungry (static code block) --");
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); }}Copy the code
Running results:
The advantages and disadvantages
This approach is similar to “hungry (static constant)”, but puts the instantiation of a class in a static block of code. Code that executes a static block of code when the class is loaded. So the pros and cons are the same.
- Summary: This method works, but it may be a waste of memory
③ Lazy (threads are not safe)
public class Singleton {
/ / 2. The first statement
private static Singleton singleton;
//1. Private constructor
private Singleton(a){}/ / LanHanShi
//3. Provide a static public method that creates a singleton when the getInstance method is called
public static Singleton getInstance(a){
if(singleton == null){
singleton = new Singleton();
}
returnsingleton; }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
System.out.println("-- lazy (thread unsafe) --");
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); }}Copy the code
Running results:
The advantages and disadvantages
- Advantages: Lazy loading
- Disadvantages: Can only be used in a single thread, not multithreading.
- why: In multithreading, if thread A executes to
if(singleton == null)
But before the code can proceed, thread B also executes the null statement, and then it willGenerate multiple instances. So youNo longer a singleton pattern 了 - Summary: In real development, don’t use this approach
④ Lazy (thread-safe, synchronous method)
public class Singleton {
/ / 2. The first statement
private static Singleton singleton;
//1. Private constructor
private Singleton(a){}/ / LanHanShi
//3. Provide a static public method, adding synchronized to solve the thread-safe problem of creating a singleton object when calling getInstance
public static synchronized Singleton getInstance(a){
if(singleton == null){
singleton = new Singleton();
}
returnsingleton; }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
System.out.println("-- lazy (thread-safe, synchronous method) --");
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); }}Copy the code
Running results:
The advantages and disadvantages
- Advantages: Lazy loading effect, and solve the problem of thread insecurity
- Disadvantages: synchronized must be used to ensure the singleton, but locking will affect the efficiency, most of the cases do not need synchronization.
- whyEach thread executes when it wants to obtain an instance of a class
getInstance()
Methods are synchronized. In fact, this method only executes the instantiation code once, later to obtain the class instance, should be directlyreturn
Will do. This leads to inefficient execution of this code - Summary: In practical development, this approach is not recommended
⑤ Lazy (thread-safe, synchronized code blocks)
public class Singleton {
/ / 2. The first statement
private static Singleton singleton;
//1. Private constructor
private Singleton(a){}/ / LanHanShi
//3. Provide a static public method
public static Singleton getInstance(a){
if(singleton == null) {synchronized (Singleton.class) {
singleton = newSingleton(); }}returnsingleton; }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
System.out.println("-- lazy (thread-safe, synchronized code block) --");
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); }}Copy the code
Running results:
The advantages and disadvantages
This is meant to be an improvement on the lazy (thread-safe, synchronized method) approach, which is so inefficient that it instead synchronizes blocks of code that generate instances. However, this approach does not allow for thread synchronization. The same problem occurs when multiple threads enter the statement if(Singleton == NULL) at the same time
- Summary: In real development, you can’t use this approach
⑥ Double-check (recommended)
public class Singleton {
//2. Declare volatile to prevent directive reorders
private static volatile Singleton singleton;
//1. Private constructor
private Singleton(a){}/ / LanHanShi
//3. Provide a static public method to add double-checked code to solve thread-safety problems and lazy loading problems, generate singleton objects
public static Singleton getInstance(a){
if(singleton == null) {synchronized (Singleton.class) {
if(singleton == null) {
singleton = newSingleton(); }}}returnsingleton; }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
System.out.println("-- double check --");
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); }}Copy the code
Running results:
The advantages and disadvantages
- advantages: Used twice
if(singleton == null)
To ensure thread-safety, the instantiation code is executed only once and only the first time it is accessed laterif(singleton == null)
You can return the object directly and avoid repeated method synchronization. - Disadvantages: There are no obvious disadvantages, but the implementation is slightly more complicated than other methods.
- Summary: This way, thread-safe; Lazy loading; This method is highly efficient and is recommended for practical development
7. Static inner class
public class Singleton {
//1. Private constructor
private Singleton(a){}/** * 1. Static inner classes will not be loaded when the Singleton class is loaded. * 2. Thread-safe when calling static properties of static inner classes. * /
// Static inner class with a static attribute Singleton
private static class SingletonInstance{
private static Singleton SINGLETON = new Singleton();
}
/ / to provide a public static method, direct return SingletonInstance. SINGLETON
public static Singleton getInstance(a){
returnSingletonInstance.SINGLETON; }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
System.out.println("-- Static inner class --");
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); }}Copy the code
Running results:
The advantages and disadvantages
- advantages: This way is used
classloader
Mechanism to ensure that the instance is initialized with only one thread. The static inner class approach has two characteristics:1Static inner classSingletonInstance
inSingleton
Classes are not instantiated immediately when they are loaded, but are called when they need to be instantiatedgetInstance
Method will be loaded and thus completedSingleton
Instantiation of.2Class static properties are initialized only when the class is first loaded, so in this case,JVM
This helps us keep the thread safe, so that no other thread can enter the class when it is initialized. - Disadvantages: No obvious disadvantages at present.
- Summary: This method avoids thread insecurity and uses the characteristics of static inner class to realize lazy loading, which is highly efficient and recommended for practical development
⑧ Enumeration [Recommended]
public enum Singleton{
INSTNACE;
// Test the method being called
public void sayOk(a){
System.out.println("ok~"); }}Copy the code
Tests verify singleton effects:
public class Test {
public static void main(String[] args) {
System.out.println("-- enumeration mode --");
Singleton a = Singleton.INSTNACE;
Singleton b = Singleton.INSTNACE;
System.out.println("Is it the same object?"+(a == b));
System.out.println("a的HashCode:"+a.hashCode());
System.out.println("b的HashCode:"+b.hashCode()); a.sayOk(); b.sayOk(); }}Copy the code
Running results:
The advantages and disadvantages
- Advantages: Singleton through enumeration, more concise, automatic support serialization mechanism, not only can avoid the problem of multi-thread synchronization, but also can prevent deserialization to create new objects
- Cons: can only be used after JDK1.5
- Summary: Recommended for practical development
Matters needing attention
The singleton mode ensures that only one object of the class exists in the system memory, saving system resources. For some objects that need to be created and destroyed frequently, the singleton mode can improve system performance.
The singleton pattern uses the following scenarios:
- Objects that need to be created and destroyed frequently
- Frequently used objects that take too much time or resources to create (i.e., heavyweight objects)
- Utility class object
- Objects that frequently access databases or files (such as data sources,session factories)