(a) A single example of the model detailed

Source: Internet
Author: User
Tags set set

Reprint: http://www.cnblogs.com/zuoxiaolong/p/pattern2.html

In the previous chapter, we learned about the concept of design patterns, why we should learn design patterns, and the six principles that should be adhered to in the design of our systems, and this chapter we will begin to learn about the 23-clock design pattern in Gof.

I have been thinking about how to interpret so many design patterns, because there are a lot of ready-made, available for learning information, I think there is a place where you can follow my rhythm to learn, rather than the online information, where the advantages, thinking for a long time, I think the only advantage, or I can have the advantage, is simple and easy to understand.

Following the main idea is easy to understand, let's first look at why the singleton pattern appears, or what kind of class can be made into a single case.

In my work, I found that all classes that can use singleton patterns have a common denominator, that is, the class does not have its own state, in other words, these classes, no matter how many you instantiate, are actually the same, and more importantly, if the class has two or more than two instances, My program actually generates a program error or a logic error that goes against the reality.

In this case, if we do not control this class into a singleton structure, there will be many instances of the same class in the application, which can be very wasteful of the system's memory resources, and can easily lead to errors and even errors, so our singleton model is expected to target or use it for the purpose of Save memory space as much as possible, reduce unnecessary GC consumption, and make your application work.

I would like to summarize a little, the most common place to make a single case, the most easy to distinguish is that these classes, in the application if there are two or more than two instances will cause errors, or I in other words, is these classes, throughout the application, at the same time, there is only one state.

In general practice, there are many application-level resources will be made into singleton, such as profile information, logically speaking, the entire application has and only in the same time there is one, of course, if you have more than one, this may not cause a program-level error, this refers to the error referred to as exception or error. But when we tried to change the configuration file, the problem came out.

You have two options, the first of which is to update all instances to the same state. The second is to wait for the problem to occur.

However, most of the problems that arise are errors at the logical level, and the individual feels that this is a more serious error than a program error, because it does not tell you the null pointer, does not tell you illegal parameters, and is often not discovered until it affects the customer's use.

Let's look at a few ways to make a single case.

In the first way, let's look at the most standard and primitive pattern of the single-mode construction.

public class Singleton {    //A static instance of    private static Singleton Singleton;    Privatization constructor    Private Singleton () {}    //gives a common static method to return a singleton public to    static Singleton getinstance () {        if (singleton = = null) {            singleton = new Singleton ();        }        return singleton;}    }

This is the way the standard singleton pattern is constructed without considering concurrent access, a way that restricts the instances we fetch to are unique through several places.

1. Static instances, properties with the static keyword are unique within each class.

2. Restricting the creation of arbitrary instances of the client, that is, the privatization of the construction method, this is the most important step to ensure the single case.

3. Give a public a static method of obtaining an instance, note that it is a static method, because this method is provided to the client when we do not get to the instance, so if it is non-static, then it becomes a contradiction, because the non-static method must have an instance to be called.

4. The constructor method is called to create an instance if only the static instance being held is null, otherwise it is returned directly.

If you go to interview a company, give you a question, let you write a singleton model example, then if you are just out of college students, you can write the above example, if I am the interviewer, out of 100, I will give 90 points, the remaining 10 points is to give better people a higher level. But if you are a person with two or three years of work experience, if you write the above example, I guess I will give you a maximum of 30 points, even if the mood in case of bad words may not give.

Why the same example is so different from the other people is that because of the situation I mentioned earlier, there is no problem with the above example without considering concurrent access.

As to why the above example is not safe in the concurrency situation, I am here to give you a concurrent example, to illustrate that the case of the singleton pattern, it is possible to create a number of instances, I myself tested about 100 times, most of the time, unexpectedly created 3 instances. Here's the code, which runs about 10 times (concurrency is probabilistic, 10 times is conservative, maybe once or 100 times) and we've created more than one instance.

Import Java.util.collections;import Java.util.hashset;import Java.util.set;import Java.util.concurrent.executorservice;import Java.util.concurrent.executors;public class TestSingleton {Boolean vol        Atile lock;    public Boolean Islock () {return lock;    } public void Setlock (Boolean lock) {this.lock = lock;  public static void Main (string[] args) throws Interruptedexception {final set<string> Instanceset =        Collections.synchronizedset (New hashset<string> ());        Final Testsingleton lock = new Testsingleton ();        Lock.setlock (TRUE);        Executorservice Executorservice = Executors.newcachedthreadpool (); for (int i = 0; i < i++) {Executorservice.execute (new Runnable () {Publ                            IC void Run () {while (true) {if (!lock.islock ()) {                        Singleton Singleton = Singleton.getinstance ();    Instanceset.add (Singleton.tostring ());                        Break        }                    }                }            });        } thread.sleep (5000);        Lock.setlock (FALSE);        Thread.Sleep (5000);        SYSTEM.OUT.PRINTLN ("------instances------We take in case of concurrency");        for (String instance:instanceset) {System.out.println (instance);    } executorservice.shutdown (); }}

I opened 100 threads at the same time in the program, went to access the GetInstance method, and loaded the instance string obtained by the ToString method of the instance into a synchronous set set, the set set will be automatically removed, so see if the result outputs two or more than two instance strings, This means that we have multiple instances in the process of concurrent access.

The program lets the main thread sleep two times, the first time to give enough time for all 100 threads to turn on, and the second is to open the lock to ensure that all the threads have called the GetInstance method.

Well, here we illustrate with the facts, the above-mentioned single example, we can create a number of instances, as for why here to explain a little, although I have always liked to speak with the facts, including reading, I do not like the author and I explain why, but hope to give me an example, let me to confirm.

The reason for this is because, when concurrent access, the first call to the GetInstance method of thread A, when the end of the singleton is null, thread A into the IF block ready to create an instance, but at the same time another thread B is not created before the instance, The singleton is also a null judgment, then Singleton is still null, so thread B will also enter the IF block to create an instance, then the problem comes out, there are two threads have entered the if block to create instances, resulting in a singleton mode is not a single case.

To avoid this, we have to think about concurrency, and the easiest way to think about it is to just synchronize the entire method in the following way.

public class Badsynchronizedsingleton {    //A static instance of    private static Badsynchronizedsingleton Synchronizedsingleton;    Privatization constructor    Private Badsynchronizedsingleton () {}    //gives a public static method to return a single instance of    synchronized static Badsynchronizedsingleton getinstance () {        if (Synchronizedsingleton = = null) {            Synchronizedsingleton = new Badsynchronizedsingleton ();        }        return Synchronizedsingleton;    }    }

The simple approach is to synchronize the whole method of getting instances, so that when one thread accesses this method, all other threads are in a pending state, which avoids the danger of just synchronizing access to create multiple instances, but I just want to say that the design is awful This will cause a lot of unnecessary waiting, so in order to express my anger, I add bad to the class name.

In fact, we just need to synchronize the place in the case of a single instance has not been created, after the instance is created, the method of obtaining the instance does not need to synchronize control again, so we will change the above example to many textbooks in the standard version of the single model, also known as double lock .

public class Synchronizedsingleton {    //A static instance of    private static Synchronizedsingleton Synchronizedsingleton;    Privatization constructor    Private Synchronizedsingleton () {}    //gives a public static method to return a single instance of the common static    Synchronizedsingleton GetInstance () {        if (Synchronizedsingleton = = null) {            synchronized (synchronizedsingleton.class) {                if ( Synchronizedsingleton = = null) {                    Synchronizedsingleton = new Synchronizedsingleton ();}}        }        return Synchronizedsingleton;}    }

This approach is much better than the most brain-free synchronous approach above, because we are only synchronizing the current instance as null, that is, when the instance is not created, or it is returned directly, thus saving a lot of unnecessary thread waiting time, notably in the synchronization block, We once again judge whether Synchronizedsingleton is null, explaining why we should do so.

Assuming we remove the null in the synchronous block, there is a case where both the A thread and the B thread judge the Synchronizedsingleton null outside the synchronization block, and the result a thread first acquires the thread lock, enters the synchronization block, and a thread creates an instance, At this point, Synchronizedsingleton has been given an instance, a thread exits the synchronization block, directly returns the first created instance, when the B thread acquires the thread lock, also enters the synchronization block, at this time a thread has actually created a good instance, B thread normal condition should return directly, However, because there is no judgment in the synchronization block is null, is directly a statement to create an instance, so the B thread will also create an instance to return, at this time caused the creation of multiple instances of the case.

After the analysis, it seems that the above two-lock example appears to be no problem, but if further in-depth consideration, in fact, there are still problems.

If we go deep into the JVM and explore the code above, it's possible (note that there is only a possibility) that there is a problem.

Because a virtual machine performs this step of creating an instance, it is actually a few steps away, meaning that creating a new object is not an atomic operation. There are no problems with the above practices in some JVMs, but in some cases they can cause inexplicable errors.

The first thing to understand is that when a JVM creates a new object, it takes three steps.

1. Allocating Memory

2. Initialize the constructor

3. Point the object to the address of the allocated memory

This order is not problematic in the dual-lock approach described above, because in this case the JVM completes the construction of the entire object to give the memory address to the object. However, if the 2 and 3 steps are reversed (2 and 3 may be reversed because the JVM is tuned for bytecode, and one of them is tuning the order of execution of the instructions), there is a problem.

Because this will first assign the memory address to the object, for the above double lock, that is, the allocated memory address to Synchronizedsingleton, and then the initialization of the constructor, when the subsequent thread to request the GetInstance method, The Synchronizedsingleton object is considered to be instantiated and returns a reference directly. If the thread uses Synchronizedsingleton before the constructor is initialized, there is an inexplicable error.

So we can not completely avoid the error at the language level, we only have to give the task to the JVM, so there is a standard singleton pattern. as shown below.

Package Com.oneinstance;public class Innerclasssingleton {public        static Singleton getinstance () {        return Singleton.singleton;    }    private static class singleton{                protected static Singleton Singleton = new Singleton ();}            }

First of all, why this kind of way avoids the above inexplicable error, mainly because the static property of a class is initialized only the first time the class is loaded, which is guaranteed by the JVM, so we do not have to worry about the problem of concurrent access. So when the initialization is done in half, the other threads are unusable because the JVM will help us force the process to synchronize. In addition, because static variables are initialized only once, Singleton is still a singleton.

The above notation is that we use static internal classes as a singleton, which is not quite in line with our habits. So we changed to the following form.

public class Singleton {        private Singleton () {} public        static Singleton getinstance () {        return singletoninstance.instance;    }        private static class singletoninstance{                static Singleton instance = new Singleton ();}            }

OK, here we go, the singleton mode is already complete. The final product is the form described above. The above forms guarantee the following points.

The 1.Singleton has at most one instance, without the consideration of reflection forcing a breach of access restrictions.

2. When concurrent access is ensured, no multiple instances are generated due to concurrency.

3. In the case of concurrent access, the instance that has not been properly initialized is not used because the initialization action is not fully completed.

The following is a less common way, here is just for your reference, not recommended to use the following methods.

The first kind, is commonly known as the a hungry man-type loading .

public class Singleton {        private static Singleton Singleton = new Singleton ();        Private Singleton () {} public        static Singleton getinstance () {        return Singleton;    }    }

The above approach is similar to the one we gave last, but the main drawback of this approach is that once I visit any of the other static domains of Singleton, it causes the initialization of the instance, and the fact is that it is possible that we did not use this instance from the beginning to the end, resulting in a waste of memory.

However, there are times when direct initialization of a singleton instance is harmless and has little impact on the project, such as the configuration file that we need to load when the app starts, and so on, which we can use to guarantee the singleton.

The second kind I do not post, and the double lock is exactly the same, just give the static instance property plus keyword volatile, it is not necessary to identify this property is optimized.

This also does not occur when the instantiation occurs in half, because the addition of the volatile keyword, is tantamount to prohibit the JVM automatic command reordering optimization, and forcibly ensure that any write to the variable in the thread is instantly visible to other threads. There is no space to introduce volatile and the specific actions that are made when variables are accessed in the JVM, in short, volatile will force all of the read and fetch operations of the variable into a non-split action. If the reader is interested, you can find some information on your own to see the relevant content.

However, it is worth noting that The volatile keyword is given meaning after JDK1.5 and 1.5, so this is not available after JDK1.5 and 1.5, but it is still not recommended, because the code is relatively complex, and because the JDK version limitations can sometimes be inconvenient.

Well, the above is basically the common pattern of all the single-mode construction, if the next interview let you write a singleton mode, there is time to put all the above all to the interviewer and the pros and cons to tell him, so that the estimated offer has been away from you.

The sharing of this singleton mode is over, thank you for watching.

Next announcement, Agent mode.

(a) A single example of the model detailed

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.