Java improvement--a singleton model

Source: Internet
Author: User

Introduced

In our daily work we often need to keep a unique instance in the application, such as: IO processing, database operation, etc., because these objects occupy important system resources, so we must limit the creation of these instances or always use a common instance, this is what we are going to introduce today-- Singleton mode (Singleton).

Singleton mode (Singleton pattern) is one of the simplest design patterns in Java. This type of design pattern belongs to the Create pattern, which provides an optimal way to create an object.

This pattern involves a single class that is responsible for creating its own objects, while ensuring that only a single object is created. This class provides a way to access its only object, which can be accessed directly without instantiating an object of that class.

Attention:

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

Realize

We know that the generation of objects of a class is done by a class constructor. If a class provides a public construction method to the outside world, the object of the class can be created arbitrarily. So, if you want to restrict the creation of objects, one way is to make the constructor private (at least protected) so that the outside class cannot produce the object by reference. At the same time, in order to ensure the availability of the class, it is necessary to provide a own object and a static method to access the object.

The idea of implementing a singleton pattern is that a class can return an object with a reference (always the same) and a method that obtains the instance (which must be a static method, usually using the name getinstance); When we call this method, the reference is returned if the class holds a reference that is not empty. If the class holds a reference that is empty, create an instance of the class and give the instance a reference to the class, and we also define the class's constructor as a private method, so that the other code cannot instantiate the object of that class by calling its constructor. Only the static method provided by the class is used to obtain a unique instance of the class.

We will create a Singleobject class. The Singleobject class has its own private constructor and a static instance of itself.

The Singleobject class provides a static method for the outside world to obtain a static instance of it. Singletonpatterndemo, our demo class uses the Singleobject class to get the singleobject object.

① Create a Singleton class.

Singleobject.java

 Public classSingleobject {//create an object of Singleobject   Private StaticSingleobject instance =NewSingleobject (); //let the constructor be private so that the class is not instantiated   PrivateSingleobject () {}//get the only available objects    Public StaticSingleobject getinstance () {returninstance; }    Public voidShowMessage () {System.out.println ("Hello world!"); }}

② gets the unique object from the Singleton class.

Singletonpatterndemo.java

 Public classSingletonpatterndemo { Public Static voidMain (string[] args) {//Illegal Constructors//compile-time error: Constructor Singleobject () is not visible//Singleobject object = new Singleobject (); //get the only available objectsSingleobject Object =singleobject.getinstance (); //displaying MessagesObject.showmessage (); }}

Output Result:

Hello world!
Several implementation modes of Singleton mode 1, lazy, thread insecure

Description: This approach is the most basic implementation, this implementation of the biggest problem is not support multithreading. Because there is no lock synchronized, it is strictly not a single case mode.

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

This code is straightforward and uses lazy loading (lazy loading) mode, but it has a fatal problem. When multiple threads call getinstance () in parallel, multiple instances are created. That is, in multi-threading does not work properly.

Several of the implementations described next support multithreading, but differ in performance.

2, lazy, thread-safe

The simplest way to solve the above problem is to set the entire getinstance () method to synchronous (synchronized).

Description: This approach has good lazy loading and can work well in multi-threading, but it is inefficient and does not require synchronization in 99% cases.
Advantage: The first call is initialized to avoid memory waste.
Disadvantage: Must lock the synchronized to guarantee the single case, but the lock will affect the efficiency.
The performance of getinstance () is not critical to the application (this method is used infrequently).

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

Although it is thread-safe and solves a multi-instance problem, it is not efficient. Because at any time only one thread can call the GetInstance () method. However, the synchronous operation only needs to be required on the first call (that is, if the instance is null in the IF statement, and not NULL when the instance is returned directly), that is, when the singleton instance object is first created. This leads to a double test lock.

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

Double-check lock mode (double checked locking pattern) is a method of locking with a synchronous block. The programmer calls it a double-check lock because there are two checks instance == null , one in the synchronization block and one in the synchronization block. Why do I have to check again within the synchronization block? Because there may be multiple threads that go in and out of the synchronization block, multiple instances are generated if no two checks are made within the synchronization block.

Description: This approach uses a dual-lock mechanism to maintain high performance in a secure and multi-threaded environment.
The performance of getinstance () is critical to the application.

 Public classSingleton {Private volatileStaticSingleton Singleton;//declared as volatile    PrivateSingleton () {} Public StaticSingleton Getsingleton () { If (instance = = null) {              //Single Checked            synchronized(Singleton.class) {                 If (instance = = null) {     //Double CheckedInstance =NewSingleton (); }            }        }        returninstance; }}  

Note that the volatile keyword is used above.

If you remove the volatile keyword, it is problematic. Mainly instance = new Singleton() in this sentence, this is not an atomic operation, in fact, in the JVM this sentence probably did the following 3 things.

    1. allocating memory to instance
    2. Call Singleton's constructor to initialize member variables
    3. Point the instance object to the allocated memory space (instance is non-null after performing this step)

However, there is an optimization of command reordering in the JVM's immediate compiler. In other words, the order of the second and third steps above is not guaranteed, and the final order of execution may be 1-3-2. If it is the latter, then after 3 execution, 2 is not executed, before the thread two is preempted, then instance is non-null (but not initialized), so the thread two will return directly to instance, then use, and then logically error.

So we just need to declare the instance variable to be volatile.

Some people think that the reason for using volatile is visibility, which is to ensure that the thread does not have a copy of instance locally, and each time it is read in the main memory. But it's not right, actually. The main reason for using volatile is another feature: Prohibit command reordering optimizations. That is, there is a memory barrier (generated assembly code) after the assignment operation of the volatile variable, and the read operation is not reordered before the memory barrier. For example above, the take operation must be executed after 1-2-3 or after the 1-3-2, there is no execution to 1-3 and then fetch the value of the case. From the perspective of the "first occurrence principle", it is that the write operation of a volatile variable takes precedence over the reading of the variable ("Back" is the order of time).

However, it is important to note that there is a problem with volatile double-check locks in versions prior to Java 5. The reason is that Java 5 JMM (Java memory model) is flawed, the immediate declaration of variables as volatile does not completely avoid reordering, mainly the volatile variable before and after the code still has a reordering problem. The issue of volatile masking reordering is fixed in Java 5, so it is safe to use volatile after this.

I believe you will not like this complex and implicit problem of the way, of course, we have a better way to implement a thread-safe single-case mode.

4. A Hungry man type

The A Hungry man method creates an object instance when the class is first referenced, regardless of whether it is actually required to be created.

Description : This method is more commonly used, but it is easy to produce garbage objects.
Advantages: Without locking, execution efficiency will increase.
Disadvantage: The class loads when it initializes, wasting memory.
It avoids the synchronization problem of multithreading based on classloder mechanism, however, instance is instantiated when class is loaded, although there are many reasons for class loading, most of them call getinstance method in singleton mode. However, it is not certain that there are other ways (or other static methods) that cause the class to load, when initializing instance obviously does not achieve the effect of lazy loading.

 Public class Singleton {      privatestaticnew  Singleton ();       Private Singleton () {}        Public Static Singleton getinstance () {          return  instance;      }  }

This kind of writing, if perfect, there is no need to nag so many double lock problem. The disadvantage is that it is not a lazy load mode (lazy initialization), and a single session is initialized at the beginning of the load class, even if the client does not call the GetInstance () method. The creation of a hungry man is not available in some scenarios: for example, if the creation of a Singleton instance is dependent on a parameter or configuration file, a method must be called before getinstance () to set the parameter to it, so that the singleton can not be used.

5. Registered/Static internal class

Description: This method can achieve the same effect as double lock mode, but it is easier to achieve. Using lazy initialization for a static domain should be used in this manner instead of double-lock mode. This approach applies only to static domains, and the double-lock method can be used when the instance domain requires lazy initialization.
This approach also takes advantage of the classloder mechanism to ensure that there is only one thread initialized instance, which is different from the 4th way: The 4th way, as long as the Singleton class is loaded, then the instance is instantiated (not reaching the lazy Loadin g effect), which is Singleton class is loaded, instance not necessarily initialized. Because the Singletonholder class is not actively used, the load Singletonholder class is displayed only if it is displayed by calling the GetInstance method, thus instantiating the instance. Imagine if instantiating instance is consuming resources, so you want it to delay loading, and on the other hand, do not want to instantiate when the Singleton class is loaded, because there is no way to ensure that the Singleton class may be actively used in other places to be loaded, then this time instantiate The instance is obviously inappropriate. At this time, this approach is reasonable compared to the 4th way.

 Public classSingleton {Private Static classSingletonholder {Private Static FinalSingleton INSTANCE =NewSingleton (); }      PrivateSingleton () {} Public Static FinalSingleton getinstance () {returnsingletonholder.instance; }  }  

This notation still uses the JVM itself to ensure thread safety, because Singletonholder is private, there is no way to access it except for getinstance (), so it is lazy, it is not synchronized when the instance is read, there is no performance flaw; JDK version.

6. Enum enum

Description: This implementation has not been widely used, but this is the best way to implement a singleton pattern. It is more concise, automatically supports serialization mechanisms, and absolutely prevents multiple instantiations.
This approach is advocated by effective Java author Josh Bloch, which not only avoids multithreading synchronization problems, but also automatically supports serialization mechanisms, prevents deserialization from recreating new objects, and absolutely prevents multiple instantiations. However, because of the JDK1.5 after the inclusion of the Enum feature, in this way can not be used to write people feel unfamiliar, in the actual work, but also very little use.
Private construction methods cannot be called by reflection attack.

 Public enum Singleton {      INSTANCE;        Public void Whatevermethod () {      }  }
Summarize

The characteristics of a singleton: the outside world cannot create an object through a constructor, which must provide a static method to provide a unique instance of the class to the outside world.

Implementing a single case has two considerations, ① the constructor private, does not allow the outside world through the constructor to create the object; ② returns the unique instance of the class to the outside world through an exposed static method.

In general, there are five types of patterns in a singleton: lazy, a hungry man, double-check lock, Static inner class, enumeration. All of these are thread-safe implementations, and the 1th method given at the beginning of the article is not the correct way to write.

Rule of Thumb: in general, the 1th and 2nd lazy methods are not recommended, and the 4th method of a hungry man is recommended. The 5th method of registration is used only if you want to explicitly implement the lazy loading effect. If you are involved in deserializing the creation of an object, you can attempt to use the 6th enumeration method. If there are other special requirements, consider using the 3rd type of double lock mode.

Related Documentation Links:

1. Single case Mode

2, How to correctly write a single case mode

3. Do you really write a single-case pattern?--java Implementation

4. design mode (II.)--single case mode

Java improvement--a singleton model

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.