2. Singleton mode
Singleton design pattern is one of the most commonly used design patterns in software development. That is, a class can only have one instance object in the whole system, which can be obtained and used. For example, the Runtime class representing the JVM Runtime environment.
1) Attention
-
How to ensure that there is only one instance
Constructor privatization
-
You must create this instance yourself
A static variable containing this class holds this unique instance
-
Provide this example to the whole system by yourself
Provide external access to the instance object
- Direct leakage; Get with get method of static variable
2) Common forms of implementation
1. Hungry Han style
Creating objects directly does not have thread safety problems
Hungry: in a hurry, whether you use it or not, create it first
1.1 direct instantiation of hungry Chinese style, concise and intuitive
- Note that the constructor is privatized, self created and saved with static variables, and provides instances to the outside world
package interview.singleton; //Hungry Chinese style, directly create an instance object, and the object will be created whether you need it or not public class Singleton1 { public static final Singleton1 INSTANCE=new Singleton1(); private Singleton1(){ } }
Get this object
package interview.singleton; public class TestDemp { public static void main(String[] args) { Singleton1 s=Singleton1.INSTANCE; System.out.println(s); } }
1.2 enumeration is the most concise
package interview.singleton; //Hungry man, enumeration /* * Enumeration type: indicates that there are a limited number of objects of this type. If it is limited to one, it becomes a single instance * */ public enum Singleton2 { INSTANCE }
Get object
package interview.singleton; public class TestDemp { public static void main(String[] args) { Singleton2 s=Singleton2.INSTANCE; System.out.println(s); } }
However, the result printed in this way is different from the first one. Print the object name INSTANCE directly
1.3 the form of static code block is suitable for complex instantiation
You may need to read a bunch of initialization data from the configuration file
package interview.singleton; import java.io.IOException; import java.util.Properties; public class Singleton3 { //Create it yourself and save it with static variables public static final Singleton3 INSTANCE; private String info; static { try { Properties properties=new Properties(); //Because the configuration file is placed under src, it can be loaded using class loader properties.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties")); INSTANCE= new Singleton3(properties.getProperty("info")); } catch (IOException e) { throw new RuntimeException(e); } } //Constructor privatization private Singleton3(String info){ this.info= info; } }
The corresponding configuration file/ src/single.propertites
info=sosleepy
2. Lazy style
2.1 thread unsafe, applicable to single thread
package interview.singleton; /* * Constructor privatization * Save this unique instance with a static variable * Provide a static method to get the instance object * * Lazy: delay the creation of this instance object, * */ public class Singleton4 { private static Singleton4 instance; private Singleton4(){ } public static Singleton4 getInstance(){ if(instance==null){ instance=new Singleton4(); } return instance; } }
test
package interview.singleton; public class TestDemp { public static void main(String[] args) { Singleton4 s1=Singleton4.getInstance(); Singleton4 s2=Singleton4.getInstance(); System.out.println(s1==s2); } }
Thread safety issues involved:
package interview.singleton; import java.util.concurrent.*; public class TestDemp { public static void main(String[] args) throws ExecutionException, InterruptedException { // Singleton4 s1=Singleton4.getInstance(); // Singleton4 s2=Singleton4.getInstance(); // System.out.println(s1==s2); Callable<Singleton4> c=new Callable<Singleton4>() { @Override public Singleton4 call() throws Exception { return Singleton4.getInstance(); } }; //Create thread pool ExecutorService es= Executors.newFixedThreadPool(2); Future<Singleton4> f1=es.submit(c); Future<Singleton4> f2=es.submit(c); Singleton4 s1=f1.get(); Singleton4 s2=f2.get(); System.out.println(s1==s2); es.shutdown(); } }
The output is false
2.2 thread safety (applicable to multithreading)
Solve with synchronization
package interview.singleton; public class Singleton5 { private static Singleton5 instance; private Singleton5(){ } public static Singleton5 getInstance(){ synchronized (Singleton5.class){ //The current class is a lock object if(instance==null){ instance=new Singleton5(); } return instance; } } }
package interview.singleton; import java.util.concurrent.*; public class TestDemp { public static void main(String[] args) throws ExecutionException, InterruptedException { // Singleton4 s1=Singleton4.getInstance(); // Singleton4 s2=Singleton4.getInstance(); // System.out.println(s1==s2); Callable<Singleton5> c=new Callable<Singleton5>() { @Override public Singleton5 call() throws Exception { return Singleton5.getInstance(); } }; //Create thread pool ExecutorService es= Executors.newFixedThreadPool(2); Future<Singleton5> f1=es.submit(c); Future<Singleton5> f2=es.submit(c); Singleton5 s1=f1.get(); Singleton5 s2=f2.get(); System.out.println(s1==s2); es.shutdown(); } }
Output results
true Process finished with exit code 0
For multithreading, there is no need to lock the subsequent threads. Add an if judgment to improve the performance
package interview.singleton; public class Singleton5 { private static Singleton5 instance; private Singleton5(){ } public static Singleton5 getInstance(){ if(instance==null){ synchronized (Singleton5.class){ //The current class is a lock object if(instance==null){ instance=new Singleton5(); } } } return instance; } }
2.3 static internal class form, applicable to multithreading
package interview.singleton; /* *The object is created only when the internal class is loaded and initialized *Static internal classes will not be automatically initialized with the loading and initialization of external classes. They need to be loaded and initialized separately. * Because it is created when the internal class is loaded and initialized, it is 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; } }
Summary: hungry Han style, enumeration form is the simplest; Lazy, static internal class form is the simplest.