Java Design pattern Single-instance mode (most complete and classic)

Source: Internet
Author: User

In all design patterns, Singleton mode is one of the most common design patterns in our project development, and there are many ways to implement the singleton pattern, do you know it? How do you guarantee the thread safety of a singleton mode in multithreaded mode? How to ensure that the serialized singleton object is reversed in a single case? These questions after reading this article will tell you the answer, hurry to read it!

What is a singleton mode?

Before the article began, we still need to introduce what is a singleton mode. Singleton mode is a pattern method for ensuring that a class has only one instance and provides a global access point for the entire system.

Some of the characteristics of a single case are embodied in the concept:

(1), in any case, the Singleton class always has only one instance

(2), Singleton needs to be able to provide this unique instance for the whole system


To make it easier for readers to understand these concepts, here is a description:

In a computer system, the driver objects of the thread pool, cache, log Object, dialog box, printer, and video card are often designed as singleton. These apps have more or less the functionality of the resource manager. Each computer can have several printers, but only one printer Spooler to prevent both print jobs from being output to the printer at the same time. Each computer can have several communication ports, and the system should centrally manage these communication ports to prevent a communication port from being called simultaneously by two requests. In short, the selection of Singleton mode is to avoid inconsistent state, to avoid long-running political.

Because of this feature, a singleton object is usually used as a carrier for storing configuration information in a program because it guarantees that other objects will read consistent information. For example, in a server program, the configuration information for the server may be stored in a database or file, which is read uniformly by a single object, and other objects in the service process can access the singleton object if they want to obtain the configuration information. This approach greatly simplifies configuration management in complex environments, especially in multi-threaded environments, but it can also lead to some synchronization problems as the application scenario differs.

A wide variety of single-instance implementations
1. A hungry man type single case

A hungry man Singleton refers to the instance being created before the method call. Here is the implementation code:

Package Org.mlinge.s01;public class Mysingleton {private static Mysingleton instance = new Mysingleton ();p rivate mysingle Ton () {}public static Mysingleton getinstance () {return instance;}}
The above is a single example of the implementation of the A hungry man, we take a look at the A Hungry man style in the implementation of multi-threaded, give a piece of multithreaded execution code:

Package Org.mlinge.s01;public class MyThread extends thread{  @Overridepublic void Run () {System.out.println ( Mysingleton.getinstance (). Hashcode ());}  public static void Main (string[] args) {mythread[] mts = new Mythread[10];for (int i = 0; i < mts.length; i++) {mts[i] = new MyThread ();} for (int j = 0; J < Mts.length; J + +) {Mts[j].start ();}}}
The above code runs the result:

1718900954171890095417189009541718900954171890095417189009541718900954171890095417189009541718900954
It can be seen from the running result that the hashcode value of the instance variable is identical, which indicates that the object is the same, and the A Hungry man is implemented by single example.

2, lazy-type single case

Lazy Singleton is an instance created when a method call gets an instance, because the relative a hungry man is "not urgent", so it is called "lazy mode". Here is the implementation code:

Package Org.mlinge.s02;public class Mysingleton {private static Mysingleton instance = Null;private Mysingleton () {} public static Mysingleton getinstance () {if (instance = = NULL) {//lazy-instance = new Mysingleton ();} return instance;}}
Here to realize the lazy type of single case, but familiar with multi-threaded concurrent programming friends should be able to see that in multi-threaded concurrency under such implementation is not guaranteed instances of the unique, and even can say that the failure is completely wrong, the following we look at the implementation of multi-threaded concurrency, here to see the effect, Let's make a few changes to the above code:

Package Org.mlinge.s02;public class Mysingleton {private static Mysingleton instance = Null;private Mysingleton () {} public static Mysingleton getinstance () {try {if (instance! = NULL) {//lazy}else{//may have some preparatory time-consuming work before creating an instance Thread.Sleep (300) ; instance = new Mysingleton ();}} catch (Interruptedexception e) {e.printstacktrace ();} return instance;}}
Here it is assumed that there are some preparatory time-consuming tasks to process before creating the instance, multithreading calls:

Package Org.mlinge.s02;public class MyThread extends thread{  @Overridepublic void Run () {System.out.println ( Mysingleton.getinstance (). Hashcode ());}  public static void Main (string[] args) {mythread[] mts = new Mythread[10];for (int i = 0; i < mts.length; i++) {mts[i] = new MyThread ();} for (int j = 0; J < Mts.length; J + +) {Mts[j].start ();}}}
The results of the implementation are as follows:

12104205681210420568193512345017189009541481297610186326487936953979512104205681210420568602269801
From the implementation of the results here, we can see that the single case of thread safety is not guaranteed, how to solve it?

3, Thread-safe Lazy single case

To ensure thread safety, we need to use a synchronous lock mechanism, and let's look at how we can step through the lazy singleton (the wrong Singleton) that has a thread-safety problem.

(1), method declaration synchronized keyword

A non-threading security issue occurs because multiple threads can enter the getinstance () method at the same time, so only the synchronized lock synchronization of the method is required:

Package Org.mlinge.s03;public class Mysingleton {private static Mysingleton instance = Null;private Mysingleton () {} Public synchronized static Mysingleton getinstance () {try {if (instance! = NULL) {//lazy}else{//may have some preparatory time-consuming work before creating an instance Threa D.sleep (+); instance = new Mysingleton ();}} catch (Interruptedexception e) {e.printstacktrace ();} return instance;}}
At this time still using the Mythread class to verify the execution of the multi-threaded implementation, put it into the ORG.MLINGE.S03 package to run, the result is as follows:

1689058373168905837316890583731689058373168905837316890583731689058373168905837316890583731689058373
From the results of the implementation, the problem has been solved, but the implementation of this mode of operation will be very inefficient. The synchronization method is inefficient, so let's consider using a synchronous code block to implement:

(2), Synchronous code block implementation

Package Org.mlinge.s03;public class Mysingleton {private static Mysingleton instance = Null;private Mysingleton () {}// Public synchronized static Mysingleton getinstance () {public static Mysingleton getinstance () {try {synchronized (Mysingl Eton.class) {if (instance! = NULL) {//lazy}else{//may have some preparatory time-consuming work before creating an instance thread.sleep (); instance = new Mysingleton ();}} catch (Interruptedexception e) {e.printstacktrace ();} return instance;}}
The implementation here guarantees thread security under multi-threaded concurrency, but this implementation will lock all the code and be inefficient.

(3), for some important code to do a separate synchronization(may not be thread safe)

A separate synchronization for some important code, rather than a full synchronization, can greatly improve execution efficiency, let's look at:

Package Org.mlinge.s04;public class Mysingleton {private static Mysingleton instance = Null;private Mysingleton () {} publi C Static Mysingleton getinstance () {try {  if (instance! = NULL) {//lazy}else{//may have some preparatory time-consuming work before creating an instance Thread.Sleep (300) ; synchronized (mysingleton.class) {instance = new Mysingleton ();}} } catch (Interruptedexception e) {e.printstacktrace ();} return instance;}}
In this case, the same Mythread class is used to verify the execution of the multithreading, put it into the ORG.MLINGE.S04 package, and execute the result as follows:
148129761039763037818632648791210420568193512345036953979559020290117189009541689058373602269801
From the running results, this method of code block synchronization, the efficiency of the code can be improved, but it failed to keep the thread safe. It seems that further consideration should be given to how to solve this problem.

(4), DCL ( Double Check Locking) Double check lock mechanism(recommended)

In order to achieve thread safety and improve the efficiency of code execution, we can use the DCL double check lock mechanism to complete, the code is implemented as follows:

Package Org.mlinge.s05;public class Mysingleton {//Use volatile keyword to protect its visibility volatile private static Mysingleton instance = NULL ;p rivate Mysingleton () {} public static Mysingleton getinstance () {try {  if (instance! = NULL) {//lazy-type}else{// There may be some preparatory time-consuming work before the instance is created Thread.Sleep; synchronized (mysingleton.class) {if (instance = = NULL) {//two check instance = new Mysingleton ();}}} } catch (Interruptedexception e) {e.printstacktrace ();} return instance;}}
The Mythread class that validates the execution of the multithreading in the previous step is placed under the ORG.MLINGE.S05 package, and the result is as follows:
369539795369539795369539795369539795369539795369539795369539795369539795369539795369539795
From the running result, this method guarantees the thread security under multi-thread concurrency.

The volatile keyword is used to guarantee the visibility of the variables in the declaration, and two checks are used in the synchronous code block to ensure that they are not instantiated repeatedly. Both of them are combined to ensure the efficiency and the thread safety of the method.

4, using static built-in class to implement a singleton mode

DCL solves the thread security problem of multithreading concurrency, in fact, using other methods can achieve the same effect, the code is implemented as follows:

Package Org.mlinge.s06;public class Mysingleton {//inner class private static class Mysingletonhandler{private static Mysingleton instance = new Mysingleton ();} Private Mysingleton () {} public static Mysingleton getinstance () {return mysingletonhandler.instance;}}
The above code is the use of static built-in class implementation of the Singleton mode, where the previous verification of the execution of multi-threaded Mythread class into the ORG.MLINGE.S06 package run, the results are as follows:
1718900954171890095417189009541718900954171890095417189009541718900954171890095417189009541718900954
From the running result, the single instance of the static inner class implementation is guaranteed by the single example under multi-thread concurrency.

5, serialization and deserialization of the single-instance mode implementation

While the static inner class guarantees thread safety for single-threaded concurrency, the result of running the default mode is multiple cases when a serialized object is encountered.

The code is implemented as follows:

Package Org.mlinge.s07;import Java.io.serializable;public class Mysingleton implements Serializable {private static Final long Serialversionuid = 1l;//Inner class private static class Mysingletonhandler{private static Mysingleton instance = new My Singleton ();} Private Mysingleton () {} public static Mysingleton getinstance () {return mysingletonhandler.instance;}}
Serialization and deserialization test code:

Package Org.mlinge.s07;import Java.io.file;import Java.io.fileinputstream;import java.io.FileNotFoundException; Import Java.io.fileoutputstream;import Java.io.ioexception;import Java.io.objectinputstream;import Java.io.objectoutputstream;public class Saveandreadforsingleton {public static void main (string[] args) {Mysingleton Singleton = Mysingleton.getinstance (); File File = new file ("MySingleton.txt"), try {fileoutputstream fos = new FileOutputStream (file); ObjectOutputStream Oos = NE W ObjectOutputStream (FOS); Oos.writeobject (singleton); Fos.close (); Oos.close (); System.out.println (Singleton.hashcode ());} catch (FileNotFoundException e) {e.printstacktrace ();} catch (IOException e) {e.printstacktrace ();} try {fileinputstream fis = new FileInputStream (file); ObjectInputStream ois = new ObjectInputStream (FIS); Mysingleton Rsingleton = (Mysingleton) ois.readobject (); Fis.close (); Ois.close (); System.out.println (Rsingleton.hashcode ());} catch (FileNotFoundException e) {e.printstacktrace ();} catch (IOexception e) {e.printstacktrace ();} catch (ClassNotFoundException e) {e.printstacktrace ();}}} 
Run the above code to get the following results:

8651139381442407170
From the results we find that the hashcode of the serial number object and the Hashcode value of the object obtained after deserialization are different, stating that the returned object is re-instantiated after deserialization, and the singleton is destroyed. So how to solve this problem?

The solution is to use the Readresolve () method in the deserialization process, and the code for the singleton implementation is as follows:

Package Org.mlinge.s07;import Java.io.objectstreamexception;import Java.io.serializable;public class MySingleton Implements Serializable {private static final long Serialversionuid = 1l;//Inner class private static class Mysingletonhandler{pri vate static Mysingleton instance = new Mysingleton (); Private Mysingleton () {} public static Mysingleton getinstance () {return mysingletonhandler.instance;} This method is called when deserializing, which is not a method of interface definition, a somewhat conventional sense protected Object readresolve () throws Objectstreamexception { System.out.println ("called The Readresolve Method! "); return mysingletonhandler.instance;}}
Run the above test code again to get the following results:

865113938 called the Readresolve Method! 865113938
From the running results, it is shown that after the addition of the Readresolve method, the instances obtained after deserialization and the same instance before serialization are guaranteed by a single instance.

6. Using static code block to implement a single case

The code in the static code block is executed when the class is used, so the implementation of this feature of the static code block can be applied to the singleton design pattern.

Package Org.mlinge.s08;public class mysingleton{private static Mysingleton instance = null; private Mysingleton () {}stati C{instance = new Mysingleton ();} public static Mysingleton getinstance () {return instance;}}
The test code is as follows:

Package Org.mlinge.s08;public class MyThread extends thread{  @Overridepublic void Run () {for (int i = 0; i < 5; i+ +) {System.out.println (Mysingleton.getinstance (). Hashcode ());}} public static void Main (string[] args) {mythread[] mts = new Mythread[3];for (int i = 0; i < mts.length; i++) {mts[i] = new MyThread ();} for (int j = 0; J < Mts.length; J + +) {Mts[j].start ();}}}
The results of the operation are as follows:

1718900954171890095417189009541718900954171890095417189009541718900954171890095417189009541718900954171890095417189009541 71890095417189009541718900954
From the running results, the single-instance thread security is guaranteed.

7. Using enumeration data type to implement Singleton mode

enum enum and static code blocks are similar in nature, when using enumerations, the constructor is automatically invoked, and this feature can be used to implement a singleton:

Package org.mlinge.s09;public enum enumfactory{singletonfactory;        Private Mysingleton instance;    The constructor of the private Enumfactory () {//enum class is instantiated in class loading instance = new Mysingleton ();    } public Mysingleton getinstance () {return instance; }}class mysingleton{//need to implement a singleton class, such as database connection connection public Mysingleton () {}}
The test code is as follows:

Package Org.mlinge.s09;public class MyThread extends thread{  @Overridepublic void Run () {System.out.println ( EnumFactory.singletonFactory.getInstance (). Hashcode ());}  public static void Main (string[] args) {mythread[] mts = new Mythread[10];for (int i = 0; i < mts.length; i++) {mts[i] = new MyThread ();} for (int j = 0; J < Mts.length; J + +) {Mts[j].start ();}}}
Results obtained after execution:
1481297610148129761014812976101481297610148129761014812976101481297610148129761014812976101481297610
The results of the operation show that the single case is guaranteed, but the enumeration class is completely exposed and is said to violate the "single principle of responsibility", so let's look at how we can transform it.

8. Perfect using Enum enumeration to implement Singleton mode

The encapsulation code that does not expose the implementation details of the enumeration class is as follows:

Package Org.mlinge.s10;public class classfactory{private enum Myenumsingleton{singletonfactory;private Mysingleton Instance;private Myenumsingleton () {//Enum class construction method is instantiated in class loading instance = new Mysingleton (); public Mysingleton getinstance () {return instance;}}  public static Mysingleton getinstance () {return MyEnumSingleton.singletonFactory.getInstance ();}} Class mysingleton{//need to implement singleton classes, such as database connection Connectionpublic Mysingleton () {}}
The code to validate the singleton implementation is as follows:

Package Org.mlinge.s10;public class MyThread extends thread{  @Overridepublic void Run () {System.out.println ( Classfactory.getinstance (). Hashcode ());}  public static void Main (string[] args) {mythread[] mts = new Mythread[10];for (int i = 0; i < mts.length; i++) {mts[i] = new MyThread ();} for (int j = 0; J < Mts.length; J + +) {Mts[j].start ();}}}
Validation results:

1935123450193512345019351234501935123450193512345019351234501935123450193512345019351234501935123450
The verification results show that the perfect single example is more reasonable.

The above is the introduction of all of the implementation of the singleton model, I believe that the readers have read the beginning of the article the introduction of the few questions, I wish you a happy reading:-d!


Note: This paper's writing ideas and examples of the source code reference "Java multithreaded Programming Core technology"-(Gaohong) a book in the sixth chapter of the study case writing.


Java Design pattern Single-instance mode (most complete and classic)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.