What is the singleton design pattern
In the whole system, there is only one instance object of a class that can be obtained and used
main points
-
A class can only have one instance object
Constructor privatization
-
You must create this instance yourself
Contains a static variable of this class to store this instance
-
Provide this instance to the entire system
Provide external access to the instance
Single case design pattern classification
Single case design patterns are divided into two categories: lazy and hungry
Hungry man style: as the name suggests, I'm very hungry now. I see a bread and I'm going to eat it right away. So when the whole system is loaded, whether you use it or not, you can create it directly.
Lazy style: also very understandable. I'm very lazy and have serious procrastination. I don't do it when I have to. That is, I create this object only when I need to use it.
Hungry Chinese implementation
Because this object is created when the system loads, starving is thread safe. There are three ways to achieve hungry Han style.
Direct instantiation hungry Chinese style (concise and intuitive)
public class Singleton1 { //2. Store the instance with a static object public static final Singleton1 INSTANCE = new Singleton1(); //1. Privatization of constructor private Singleton1(){ } }
Enumeration method (the most convenient)
public enum Singleton2 { INSTANCE }
Static code block
In fact, the effect is the same, but static code blocks are more suitable for setting complex parameters during initialization
If we want to read parameters from an external configuration file when we create a parameterized construction method, we can use static code blocks to create it
public class Singleton3 { private static final Singleton3 INSTANCE; static { INSTANCE = new Singleton3(); } private Singleton3(){ } }
Lazy implementation
Thread unsafe (for single thread)
public class Singleton4 { //2. Store the instance with a static object private static Singleton4 INSTANCE; //1. Privatization of constructor private Singleton4(){ } //3. Expose examples through methods public static Singleton4 getInstance(){ if(INSTANCE == null){ INSTANCE = new Singleton4(); } return INSTANCE; } }
You can test thread insecurity by
public class Singletontest4 { public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<Singleton4> c = new Callable<Singleton4>() { @Override public Singleton4 call() throws Exception { Singleton4 s = Singleton4.getInstance(); return s; } }; ExecutorService es = Executors.newFixedThreadPool(2); Future<Singleton4> submit1 = es.submit(c); Future<Singleton4> submit2 = es.submit(c); Singleton4 s1 = submit1.get(); Singleton4 s2 = submit2.get(); System.out.println(s1); System.out.println(s2); } }
Thread safe (for multithreading)
Thread security is nothing more than adding a lock
public class Singleton5 { //2. Store the instance with a static object private static Singleton5 INSTANCE; //1. Privatization of constructor private Singleton5(){ } //3. Expose examples through methods public static Singleton5 getInstance(){ if(INSTANCE == null){ synchronized (Singleton5.class) { INSTANCE = new Singleton5(); } } return INSTANCE; } }
Static internal class form (applicable to multithreading)
Calling the initialization method into a static internal class is absolutely thread safe.
public class Singleton6 { private Singleton6(){ } private static class Inner{ private static final Singleton6 INSTANCE = new Singleton6(); } public static Singleton6 getInstance(){ return Inner.INSTANCE; } }