[Go] Do you really write a singleton pattern?--java implementation

Source: Internet
Author: User

Do you really write a singleton pattern?--java implementation

Original: Http://www.tuicool.com/articles/MBrUfy6

The singleton mode may be the least code mode, but less does not necessarily mean simple, want to use good, with the singleton mode, it really cost a brain. This paper makes a summary of the common pattern in Java, if there are errors or omissions, please correct the reader.

A hungry man method

As the name implies, 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. The code is as follows:

 Public class Singleton {       privatestaticnew  Singleton ();     Private Singleton () {}      Public Static Getsignleton () {        return  singleton;    }}

The benefit of this is that writing is simple, but it is not possible to delay the creation of objects. But most of the time we want the object to delay loading as much as possible to reduce the load, so we need the following lazy method:

Single thread notation

This notation is the simplest, consisting of a private constructor and a public static factory method, which singleton null in the factory method, and if NULL is the new one, and finally returns the Singleton object. This approach allows for delayed loading, but there is a fatal weakness: thread insecurity. If you have two threads that call the Getsingleton () method at the same time, there is a great chance that the object will be created repeatedly.

 Public class Singleton {    privatestaticnull;     Private Singleton () {}      Public Static Singleton Getsingleton () {        ifnullnew  Singleton ();         return Singleton;}    }
Consider thread-safe notation

This notation takes into account thread safety and locks the null judgment on Singleton and the new part using synchronized. At the same time, the Singleton object is restricted by using the volatile keyword, guaranteeing its visibility to all threads, and prohibiting command reordering optimizations. It is thus possible to semantically guarantee that this singleton pattern is thread-safe. Note that this is said to be semantically, the actual use of the existence of small pits, will be written in the following text.

 Public classSingleton {Private Static volatileSingleton Singleton =NULL; PrivateSingleton () {} Public StaticSingleton Getsingleton () {synchronized(Singleton.class){            if(Singleton = =NULL) {Singleton=NewSingleton (); }        }        returnSingleton; }    }

Take into account the thread safety and efficiency of the wording

Although the above-mentioned notation can be run correctly, it is inefficient and cannot be applied in practice. Because every time you call the Getsingleton () method, you have to queue up here at synchronized, and it is very rare to actually encounter a new situation. Therefore, a third form of writing is Born:

 Public classSingleton {Private Static volatileSingleton Singleton =NULL; PrivateSingleton () {} Public StaticSingleton Getsingleton () {if(Singleton = =NULL){            synchronized(Singleton.class){                if(Singleton = =NULL) {Singleton=NewSingleton (); }            }        }        returnSingleton; }    }

This notation is called a "double-check lock", as the name implies, in the Getsingleton () method, two times the null check. Seemingly superfluous, but actually dramatically increases concurrency, which in turn improves performance. Why is it possible to increase the degree of concurrency? As mentioned above, the case of new in the Singleton is very small, and the vast majority of them are read operations that can be parallel. Therefore, more than one null check before locking can reduce the vast majority of lock operation, the efficiency of the implementation of the goal is achieved.

Keng

So is this a perfectly safe formulation? As I said earlier, there is no problem from a semantic point of view. But there is still a pit. Before we say this hole, we have to look at the volatile keyword. In fact, this keyword has two layers of semantics. The first layer of semantics is believed to be more familiar and visible to all. Visibility refers to the modification of the variable in a thread that is immediately written back to the main memory by the work memory, so it is immediately reflected in the read operation of the other thread. By the way, working memory and main memory can be approximately understood as the actual computer cache and primary storage, the working memory is the thread exclusive, main memory is thread-shared. The second layer of volatile semantics is the prohibition of command reordering optimizations. We know that the code we write (especially multithreaded code), because of compiler optimizations, may actually be executed in a different order than we write. The compiler only guarantees that the program executes the same results as the source code, but does not guarantee that the order of the actual instructions is the same as the source code. This looks fine on a single thread, but once multiple threads are introduced, this disorder can cause serious problems. The volatile keyword can be used to solve this problem semantically.

Note that "There is no semantic problem" mentioned repeatedly, but unfortunately, it is not possible to disable the instruction rearrangement optimization until jdk1.5 will work correctly. Even declaring variables as volatile in the previous JDK did not completely avoid the problem caused by reordering. Therefore, in the jdk1.5 version, the double check lock form of the singleton mode is not guaranteed to be thread-safe.

Static internal class method

So, is there a time-lapse load and a simple way to keep thread safe? We can put the singleton instance into a static inner class, which avoids the creation of the static instance when the Singleton class is loaded, and because the static inner class is only loaded once, this is also thread-safe:

 Public class Singleton {    privatestaticclass  Holder {        private Static New Singleton ();    }     Private Singleton () {}      Public Static Singleton Getsingleton () {        return  Holder.singleton;    }}

However, there are two common drawbacks to all of the implementations mentioned above:

    • Requires additional work (Serializable, transient, readresolve ()) to serialize, or a new instance is created each time a serialized object instance is deserialized.
    • You might be forced to call our private constructor with reflection (if you want to avoid this, you can modify the constructor so that it throws an exception when creating the second instance).
Enumeration notation

Of course, there is a more elegant way to implement the singleton pattern, which is the enumeration notation:

 Public enum Singleton {    INSTANCE;     Private String name;      Public String GetName () {        return  name;    }      Public void setName (String name) {        this. Name = name;    }} 

The use of enumerations, in addition to thread-safe and anti-reflection forced invocation of the constructor, also provides an automatic serialization mechanism to prevent deserialization when a new object is created. Therefore, effective Java recommends using enumerations as much as possible to implement the singleton.

Summarize

This article sent out after a lot of feedback, it makes me feel flattered, think should write a little summary. The code is not written once and for all, only in the most appropriate wording under certain conditions. Under different platforms and different development environments (especially JDK versions), there are different optimal solutions (or better solutions).

For example, enumeration, although effective Java is recommended, but on the Android platform is not recommended. Clearly stated in this Android Training:

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.

Again, such as double-check lock method, can not be used before jdk1.5, and on the Android platform is more comfortable to use (generally Android is more than jdk1.6, not only fixed the volatile semantic problem, but also added a lot of lock optimization, so that the cost of multi-threaded synchronization to reduce a lot).

Finally, regardless of the approach, keep in mind the three main points of the single case:

    • Thread Safety
    • Lazy Loading
    • Serialization and deserialization security
Resources

"Effective Java (second edition)"

"In-depth understanding of Java Virtual Machine--JVM advanced features and Best Practices (second Edition)"

[Go] Do you really write a singleton pattern?--java implementation

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.