Java improvements-singleton mode and java example Mode

Source: Internet
Author: User

Java improvements-singleton mode and java example Mode
Introduction

In our daily work, we often need to keep a unique instance in the application, such as IO processing and database operations. Because these objects all occupy important system resources, therefore, we must restrict the creation of these instances or always use a public instance. This is what we will introduce today-Singleton mode ).

Singleton Pattern is one of the simplest Design Patterns in Java. This type of design mode belongs to the creation mode, which provides an optimal way to create objects.

This mode involves a single class, which is responsible for creating its own objects and ensuring that only a single object is created. This class provides a way to access its unique object, which can be accessed directly without instantiating the object of this class.

Note:

  • 1. A singleton class can only have one instance.
  • 2. The Singleton class must create its own unique instance.
  • 3. The Singleton class must provide this instance to all other objects.

Implementation

We know that the generation of a Class Object is completed by the class constructor. If a class providespublicSo that the external world can create any object of this class. Therefore, if you want to restrict the generation of objects, one way is to convert the constructor into private (at least protected) so that the external classes cannot generate objects by referencing them. To ensure the availability of the class, you must provide your own object and the static method for accessing this object.

The idea of implementing the singleton mode is: A class can return a reference (always the same) to an object and a method to obtain the instance (must be a static method, the getInstance name is usually used). When we call this method, if the reference held by the class is not empty, this reference is returned, if the reference of the class persistence is null, create an instance of the class and assign the instance reference to the reference of the class persistence. At the same time, we also define the constructor of the class as a private method, in this way, the code in other places cannot instantiate the object of this class by calling the constructor of this class. Only the static method provided by this class can be used to obtain the unique instance of this class.

We will createSingleObjectClass.SingleObjectClass has its own private constructor and its own static instance.

SingleObjectClass provides a static method for the outside world to obtain its static instance.SingletonPatternDemo, The usage of our demo classSingleObjectClass to obtainSingleObjectObject.

① Create a Singleton class.

SingleObject. java

Public class SingleObject {// create a SingleObject object private static SingleObject instance = new SingleObject (); // make the constructor private so that this class will not be instantiated private SingleObject () {}// obtain the only available object public static SingleObject getInstance () {return instance;} public void showMessage () {System. out. println ("Hello World! ");}}

② Obtain a unique object from the singleton class.

SingletonPatternDemo. java

Public class SingletonPatternDemo {public static void main (String [] args) {// invalid constructor // compilation error: constructor SingleObject () is invisible // SingleObject object = new SingleObject (); // obtain the unique available object SingleObject object = SingleObject. getInstance (); // display the message object. showMessage ();}}

Output result:

Hello World!
Implementation methods of Singleton Mode 1. Lazy, thread insecure

Description:This is the most basic implementation method. The biggest problem with this implementation is that multithreading is not supported. Because synchronized is not locked, it is not considered a singleton mode strictly.

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

This code is simple and clear and uses the lazy loading mode, but it has a fatal problem. When multiple threads call getInstance () in parallel, multiple instances are created. That is to say, it cannot work normally under multiple threads.

The implementation methods described in the following sections support multithreading, but the performance varies.

2. Lazy, thread security

To solve the problem above, the simplest method is to set the entire getInstance () method to synchronous (synchronized ).

Description:This method has good lazy loading and can work well in multiple threads. However, the efficiency is very low. In 99% cases, synchronization is not required.
Advantage: initialization is performed for the first call to avoid Memory waste.
Disadvantage: synchronized must be locked to ensure the Singleton, but locking will affect the efficiency.
The performance of getInstance () is not critical to applications (this method is rarely used ).

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

Although it achieves thread security and solves the problem of multiple instances, it is not efficient. At any time, only one thread can call the getInstance () method. But the synchronization operation only needs to be called for the first time (that is, it is called when the if statement determines that the instance is null, And the instance is directly returned if it is not null ), that is, when you create a single instance object for the first time. This leads to a double check lock.

3. double check lock/double check lock (DCL, namely double-checked locking)

Double checked locking pattern is a method that uses synchronous block locking. The programmer calls it a double check lock because there will be two checksinstance == null, Once out of the synchronization block, once in the synchronization block. Why do I need to test the synchronization block again? Because there may be multiple threads entering the if outside the synchronization block together, if there is no secondary check in the synchronization block, multiple instances will be generated.

Description:This method adopts the double lock mechanism, which is safe and can maintain high performance in the case of multiple threads.
The performance of getInstance () is critical to applications.

Public class Singleton {private volatile static Singleton singleton; // declare volatile private Singleton () {} public static Singleton getSingleton () {if (instance = null) {// Single Checked synchronized (Singleton. class) {if (instance = null) {// Double Checked instance = new Singleton () ;}} return instance ;}}

Note that the volatile keyword is used above.

If the volatile keyword is removed, it is problematic. Mainly lies ininstance = new Singleton()This sentence is not an atomic operation. In fact, the following three things are done in JVM.

However, optimization of Command Re-sorting exists in the JVM instant compiler. That is to say, the order of the second and third steps is not guaranteed. The final execution order may be 1-2-3 or 1-3-2. If it is the latter, it will be preempted by thread 2 before 3 is finished and 2 is not executed. At this time, the instance is not null (but it is not initialized ), therefore, thread 2 will directly return the instance and then use it. Then, an error is automatically reported.

So we only need to declare the instance variable as volatile.

Some people think that the reason for using volatile is visibility, that is, it can ensure that the thread does not have a copy of the instance locally, every time it is read from the main memory. But it is not true. Another feature of volatile is its prohibition of Command Re-sorting optimization. That is to say, there will be a memory barrier (on the generated assembly code) after the value assignment operation of the volatile variable, and the read operation will not be reordered before the memory barrier. For example, in the above example, the fetch operation must be completed after 1-2-3 or 1-3-2, and no result is obtained after 1-3. From the perspective of the "First Occurrence principle, write operations on a volatile variable are performed first and then the read operations on the variable are performed (the "back" here is the chronological order ).

However, there is still a problem with the volatile double check lock in Java 5 or earlier versions. The reason is that JMM (Java Memory Model) before Java 5 is defective, and instant variable definition as volatile cannot completely avoid rescheduling, it is mainly because the code before and after volatile variables still has the problem of re-sorting. This volatile block-sorting problem was fixed in Java 5, so you can safely use volatile after that.

I believe you will not like this complicated and implicit method. Of course, we have a better way to implement the thread-safe Singleton mode.

4. Hungry Chinese

The hungry Chinese method creates an object instance when this class is referenced for the first time, regardless of whether the instance needs to be created or not.

Description: This method is commonly used, but it is prone to spam objects.
Advantage: the execution efficiency is improved without locking.
Disadvantage: class initialization is a waste of memory.
It is based on the classloder mechanism to avoid multi-thread synchronization. However, instances are instantiated during class loading. Although there are many causes for class loading, in Singleton mode, most of them call the getInstance method, but it cannot be determined that other methods (or other static methods) cause class loading, at this time, the initialization of the instance obviously does not achieve the lazy loading effect.

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

If this writing method is perfect, there is no need to worry about so many double check locks. The disadvantage is that it is not a lazy initialization mode. It is initialized at the very beginning after the class is loaded, even if the client does not call the getInstance () method. The creation method of the hunger style will not be available in some scenarios: for example, if a Singleton instance is created based on parameters or configuration files, you must call a method to set parameters before getInstance, in this way, the singleton writing method cannot be used.

5. Registration type/static internal class

Description:This method achieves the same effect as the double check lock method, but it is easier to implement. This method should be used instead of the double check lock method to use delayed initialization for static domains. This method is only applicable to static domains. The double check lock method can be used when the instance domain needs to be delayed during initialization.
This method also uses the classloder mechanism to ensure that there is only one thread during instance initialization. It is different from the 4th method: 4th methods as long as the Singleton class is loaded, then the instance will be instantiated (the lazy loading effect is not achieved), and this method is because the Singleton class is loaded, and the instance is not necessarily initialized. Because the SingletonHolder class is not actively used, the SingletonHolder class is displayed and instantiated only when the getInstance method is called. Imagine that instantiating an instance consumes a lot of resources, so you want to delay loading. On the other hand, you do not want to instantiate the instance when loading the Singleton class, because the Singleton class cannot be actively used in other places and loaded, it is obviously inappropriate to instantiate the instance at this time. At this time, this method is more reasonable than the 4th method.

public class Singleton {      private static class SingletonHolder {          private static final Singleton INSTANCE = new Singleton();      }      private Singleton (){}      public static final Singleton getInstance() {          return SingletonHolder.INSTANCE;      }  }  

This method still uses the JVM mechanism to ensure thread security. Because SingletonHolder is private, it cannot be accessed except getInstance (), so it is lazy; at the same time, data is not synchronized when the instance is read, and there is no performance defect. It does not depend on the JDK version.

6. Enum Enumeration

Description:This implementation method has not been widely used, but it is the best way to implement the singleton mode. It is more concise and automatically supports serialization, which definitely prevents multiple instantiation.
This method is advocated by Josh Bloch, author of objective Java. It not only avoids multithreading synchronization, but also automatically supports serialization to prevent deserialization from re-creating new objects, it is absolutely prevented from being instantiated multiple times. However, since the enum feature was added only after JDK1.5, it is difficult to write in this way, and it is rarely used in actual work.
Private constructor methods cannot be called through reflection attack.

public enum Singleton {      INSTANCE;      public void whateverMethod() {      }  }
Summary

Singleton features: an object cannot be created by the constructor. This class must provide a static method to provide a unique instance of this class to the outside world.

There are two considerations for implementing a singleton: ① the constructor is private, and the outside world is not allowed to create objects through the constructor; ② the only instance of the class is returned to the outside world through a public static method.

In general, the singleton mode has five writing methods: lazy, hungry, dual-check lock, static internal class, and enumeration. All of the above are thread-safe implementations. The 1st methods provided at the beginning of this article are not correct.

Experience:Generally, we do not recommend 1st and 2nd lazy ways. We recommend that you use 4th lazy ways. Only when lazy loading is implemented explicitly can 5th registration methods be used. If deserialization is involved in object creation, you can use 6th enumeration methods. If you have other special requirements, consider using 3rd double-check locks.

Links to relevant documents:

1. Singleton Mode

2. How to correctly write the singleton Mode

3. Are you sure you want to write the singleton mode-Java Implementation

4. design mode (2) -- Singleton Mode

 

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.