[Singleton] Singleton mode, dual detection lock DCl, volatile (1)

Source: Internet
Author: User
Tags object serialization protected constructor

In Singleton mode, the most important concern is the number of object creation times and the time when the object was created.

The Singleton mode can be very simple, and only one class is needed to complete it (look at the poor UML diagram in this chapter ). However
The Singleton mode can be quite complex than the first five modes, for example, involving the DCl double checked detection (double checked
Locking), involving multiple classloaders, cross-JVM (cluster, remote EJB, etc.), and reconstruction after the destruction of the singleton object
. For complex situations, this chapter will involve some of these [1]

Purpose:

You want the object to create only one instance and provide a global access point.

Scenario:

Kerrigan is a crucial soul character for Zerg, countless drone, zergling, hydralisk ...... Can be created and sacrificed,
The existence of Kerrigan is related to the survival of Zerg in this game, and Kerrigan cannot be created multiple times. It must have an instance with only one worm blade queen.
It is a game rule, but it is a political issue.

Analysis:

The structure is simple, but we still have some small requirements as follows:

1. Basic Requirement: each time you get from getinstance (), one and only one Kerrigan object is returned.

2. A little higher requirement: Kerrigan is very busy and many people look for it, so I hope this method can adapt to multi-thread concurrent access.

3. A higher requirement: Zerg is a society that focuses on civil servant efficiency and hopes to find Kerrigan as high as possible.

4. The last requirement is Kerrigan's own proposal: Understanding Kerrigan is too tired to spend more time sleeping, Kerrigan wants to implement lazy load and be constructed only when needed.

5. I originally intended to explain how to handle multiple classloader, multiple JVM, and other situations. But I still don't want to take the case into consideration too complicated. Let's leave the author blank for the moment (-_-#).

The Singleton mode we wrote for the first time is as follows:

/*** The first attempt to implement single-instance access to Kerrigan */public class singletonkerrigana {/*** singletonkerrigana instance */Private Static singletonkerrigana instance = NULL; public static singletonkerrigana getinstance () {If (instance = NULL) {// line a instance = new singletonkerrigana (); // line B} return instance ;}}

In this way, we can check the four-point requirement from the top down and find that there is a problem at the second point. Assume that the scenario is: Concurrent calls by two threads.
Singletonkerrigana. getinstance (). Assume that when the thread first checks whether the instance is null
The position from A to line B. After the judgment is completed, JVM switches the CPU resource to thread 2, because thread 1 has not yet executed line
B, so the instance is still empty, so thread 2 executes the new
Signletonkerrigana () operation. After a moment, when the thread is awakened again, it still runs New
Signletonkerrigana () operation. Okay. The question is, who are Li Yun and Li GUI in two Kerrigan?

Next we will try the singleton mode for the second time:

/*** Second attempt to access Kerrigan in a single instance */public class singletonkerriganb {/*** singletonkerriganb instance */Private Static singletonkerriganb instance = NULL; public synchronized static singletonkerriganb getinstance () {If (instance = NULL) {instance = new singletonkerriganb ();} return instance ;}}

A Synchronized modifier is added only to the method of the first code, so it can be ensured that there will be no thread problems. However, there is a high (at least a large proportion of time consumed) performance question. In addition to the singletonkerriganb constructor executed during the first call, the instance object is directly returned for each subsequent call. The operation of the returned object takes a very small amount of time, and most of the time is spent on the synchronization preparation of the synchronized modifier. Therefore, the performance is not cost-effective.

Change the code to the following:

/*** Implement the third attempt to access Kerrigan from a single instance */public class singletonkerriganc {/*** singletonkerriganc instance */Private Static singletonkerriganc instance = NULL; public static singletonkerriganc getinstance () {synchronized (singletonkerriganc. class) {If (instance = NULL) {instance = new singletonkerriganc () ;}} return instance ;}}

Basically, it does not make sense to move synchronized into the code. Every time getinstance () is called, synchronization is still required. Synchronization itself is fine, but we only want to synchronize it when we create the Kerrigan instance for the first time. Therefore, we have written the following statement: dual lock check (DCL ).

/*** Implement the fourth attempt to access Kerrigan from a single instance */public class singletonkerrigand {/*** singletonkerrigand instance */Private Static singletonkerrigand instance = NULL; public static singletonkerrigand getinstance () {If (instance = NULL) {synchronized (singletonkerrigand. class) {If (instance = NULL) {instance = new singletonkerrigand () ;}} return instance ;}}

It seems that this has met our requirements. Except for the first object creation, other accesses will be returned in the first if, so they will not go to the synchronization block. Is it perfect?

Let's take a look at this scenario: Assume that thread 1 executes to instance = new
Singletonkerrigand () is a sentence, but in fact it is not an atomic operation (the atomic operation means that this statement is either executed or
Has not been executed, and cannot be executed in half ). In fact, there are a lot of non-atomic operations in advanced languages. We just need to look at the corresponding assembly code after the sentence is compiled and executed in JVM.
The statement is compiled into eight Assembly commands, and roughly three things are done:

1. allocate memory to Kerrigan instances.

2. initialize the Kerrigan constructor.

3. Point the instance object to the allocated memory space (note that the instance is not null in this step ).

However, the Java compiler allows the processor to execute out-of-order and jmm (Java memory
In MEDEL), the cache and register to the master memory write-back sequence is not guaranteed, that is, the execution sequence may be 1-2-3 or
1-3-2. If it is the latter, it is switched to thread 2 before 3 is finished and 2 is not executed. At this time, the instance has passed the third step in thread 1.
Point, the instance is no longer empty, so thread 2 directly takes the instance and then uses it, And then reports an error in order, and this kind of error is hard to trace and difficult to reproduce, it is estimated that the debugging is one star
They may not be able to find them. It's a coffee cup.

The DCl statement to implement Singleton is recommended in many technical books and textbooks (including books based on previous versions of jdk1.4.), which is actually not completely correct. It is true in some languages (such
C Language) DCL is feasible, depending on whether the order of steps 2 and 3 can be ensured. After jdk1.5, the official team has noticed this problem, so it adjusted jmm and embodied volatile.
Keyword. Therefore, if JDK is 1.5 or later, you only need to change the instance definition to "Private volatile static
Singletonkerrigand instance =
NULL; "to ensure that every time the instance is read from the main memory, you can use DCL to complete the singleton mode. Of course, volatile will also affect performance more or less,
The most important thing is that we need to consider jdk1.42 and earlier versions, so the improvement of the single-sample mode writing in this article is still continuing.

The code is getting more and more complex. Now let's look back at the original truth. According to the Rules in JLS (Java language specification), a class will only be initialized once in a classloader, this is ensured by the JVM itself, so we should throw the initialization of the instance to the JVM, and the code will be changed to this:

/*** Implement the fifth attempt to access Kerrigan from a single instance */public class singletonkerrigane {/*** singletonkerrigane instance */Private Static singletonkerrigane instance = new singletonkerrigane (); public static singletonkerrigane getinstance () {return instance ;}}

Well, if this writing method is perfect, the first few paragraphs are the authors entertaining readers. This method does not cause concurrency issues, but it is in the hunger style. After classloader loads the class, the Kerrigan instance will be created immediately. The Hunger style creation method will not be available in some scenarios: for example, if the creation of a Kerrigan instance is dependent on a parameter or configuration file, you must call a method to set the parameter before getinstance (), so that this Singleton method cannot be used.

Let's take a look at the following Singleton method that I think can cope with many scenarios:

/*** Implement the sixth attempt to access Kerrigan from a single instance */public class singletonkerriganf {Private Static class singletonholder {/*** single instance object instance */static final singletonkerriganf instance = new singletonkerriganf ();} public static singletonkerriganf 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.

There are many other Singleton modes, such as using a local thread (threadlocal) to process concurrency, ensuring the implementation of a singleton in a thread, and using registration in the gof original example
This method is applicable to the implementation when the singleton class needs to be inherited, and the implementation in the Multi-classloader environment using the specified class loader. When we do the development and design work, we must take into account the requirements.
Possible expansion and changes should also avoid unnecessary design improvement and implementation complexity due to "Phantom requirements", and ultimately lead to loss of construction period, performance and stability. Insufficient design and excessive design are both harmful.
There is no best Singleton mode, but only the most appropriate Singleton mode.

So far, the singleton mode has come to an end. Finally, we will introduce how to block the construction of Singleton objects in other ways:

1. New singleton object directly

2. Construct a singleton object through reflection

3. Construct a singleton object through serialization.

In the first case, we usually add a private or protected constructor, so that the system will not automatically add the public constructor. Therefore, we can only call the static method in it, you cannot create an object through new.

In the second case, you can use the setaccessible method to break through the private restriction during reflection. We need to do the first job while still
Reflectpermission ("suppressaccesschecks ")
Use the security manager's checkpermission method to limit this breakthrough. In general, it is okay not to do these things.
Through the application server for background configuration implementation.

In the third case, if the singleton object needs to implement the serializable interface (rarely), The readresolve () method should be implemented at the same time to ensure that the original object is obtained during deserialization.

Based on the above situation, two methods are added to the singleton mode:

/*** Can handle single-instance implementations in most cases */public class singletonkerrigan implements serializable {Private Static class singletonholder {/*** single-instance object instance */static final singletonkerrigan instance = new singletonkerrigan ();} public static singletonkerrigan getinstance () {return singletonholder. instance;}/*** the private constructor is used to avoid the use of new to instantiate the object. */private singletonkerrigan () {}/*** readresolve method to cope with single-instance object serialization */private object readresolve () {return getinstance ();}}

Summary:

This chapter tries again and again to understand the advantages and disadvantages of various implementation solutions of the singleton mode. I have briefly discussed the double lock detection. I believe everyone can understand from the evolution of various attempts why the singleton mode is the simplest and most complex construction mode.

 

Refer:

Http://crud0906.iteye.com/blog/576321

Http://www.javamex.com/tutorials/double_checked_locking_fixing.shtml

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.