Java single case Mode--it's not as simple as it looks __java

Source: Internet
Author: User

The single case (Singleton) pattern in Java is a widely used design pattern. The primary role of a singleton pattern is to ensure that only one instance of a class exists in a Java program. Some managers and controllers are often designed as a single case pattern.

The singleton pattern has many advantages, it avoids the duplication of instance objects, reduces the time cost of creating objects, saves memory space, and avoids logic errors caused by manipulating multiple instances. If an object has the potential to penetrate the entire application and play a role of global unified management control, then the single case pattern may be a worthwhile choice.

The single case pattern has many kinds of writing, most of which are more or less deficient. The following will be the introduction of these kinds of writing.

1, a hungry man mode

public class singleton{
    private static Singleton instance = new Singleton ();
    Private Singleton () {} public
    static Singleton newinstance () {return
        instance;
    }
}
From the code we see that the constructor of a class is defined as private, that other classes cannot instantiate this class, and then provide a static instance and return it to the caller. The A Hungry man mode is the simplest way to implement the A Hungry man pattern, which is created when the class loads, and the instance exists throughout the program cycle. The advantage of this is that the instance is created only once when the class is loaded, and there is no case of multiple threads creating multiple instances, avoiding the problem of multithreading synchronization. Its drawbacks are also obvious, even if the single example is not used and will be created, and after the class is loaded to be created, memory is wasted.

This implementation is suitable for cases where the single example consumes less memory and is used when initializing. However, if a single case occupies a larger amount of memory, or a single case is only used in a particular scenario, it is not appropriate to use the A Hungry man mode, which requires lazy mode for lazy loading.

2, lazy mode

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

The single example in the lazy mode is created when it is needed, and if a single instance has been created, invoking the fetch interface again will not re-create the new object, but rather directly return the object created earlier. If a single example is used less often and more resources are created for a single instance, then a single instance of on-demand creation is needed, and the use of lazy mode is a good choice. But the lazy mode here does not take into account thread-safety issues, where multiple threads may call its getinstance () method concurrently, causing multiple instances to be created, requiring a lock to resolve thread synchronization issues as follows.

public class singleton{
    private static Singleton instance = null;
    Private Singleton () {} public
    static synchronized Singleton newinstance () {
        if (null = = instance) {
            Instance = New Singleton ();
        }
        return instance
    }
}

3. Double check lock

The lock-idle model seems to solve the problem of threading concurrency and delay loading, yet it has a performance problem and is still not perfect. Synchronized modified synchronization method is much slower than the general method, if multiple calls to getinstance (), cumulative performance loss is relatively large. So there is a double check lock, first look at its implementation code.

public class Singleton {
    private static Singleton instance = null;
    Private Singleton () {} public
    static Singleton getinstance () {
        if (instance = = null) {
            synchronized ( Singleton.class) {
                if (instance = = null) {//2
                    instance = new Singleton ()
                ;
        }}} return instance
    }
}
You can see the above in the sync code block more than a layer of instance for empty judgments. Because a single instance object only needs to be created once, if getinstance () is called again, only the single instance object is returned directly. Therefore, in most cases, calling getinstance () does not execute to the synchronized code block, thereby improving program performance. However, it is also necessary to consider a situation if two threads a, b,a executed an if (instance = = NULL) statement, it would assume that the single Instance object was not created, and that the line Cheng Che to B also executed the same statement, B also thought that the single case object was not created, and then two threads executed the synchronized code block sequentially, And a single Instance object is created separately. To solve this problem, you also need to add the IF (instance = NULL) statement in the Sync code block, which is the code 2 above.

We see that the double check lock is implemented delay loading, and solve the problem of threading concurrency, but also solve the problem of implementation efficiency, whether it is really foolproof.

Here we mention the instruction rearrangement optimizations in Java. The so-called command rearrangement optimization means that the program runs faster by adjusting the order of the instructions without changing the original semantics. Compiler optimizations are not specified in the JVM, which means that the JVM is free to optimize instruction reordering.

The key to this problem is that because of the existence of the command rearrangement optimization, the order of initializing Singleton and assigning the object address to the instance field is indeterminate. When a thread creates a single instance object, it allocates memory space for the object and sets the field of the object to the default value before the constructor is invoked. The allocated memory address can now be assigned to the instance field, but the object may not have been initialized yet. If the next thread is called getinstance, the wrong state object is taken, and the program will fail.

The above is the double check lock will fail the reason, but fortunately in JDK1.5 and after the version added volatile keyword. One of the semantics of volatile is to prohibit the ordering of order optimization, and to ensure that the object is already initialized when the instance variable is assigned, thus avoiding the problem mentioned above. The code is as follows:

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

4. Static internal class

In addition to the above three ways, there is another way to implement a single example, through static internal classes to implement. First take a look at its implementation code:

public class singleton{
    private static class singletonholder{public
        static Singleton instance = new Singleton ();
    }
    Private Singleton () {} public
    static Singleton newinstance () {return
        singletonholder.instance;
    }
}

This approach also leverages the class loading mechanism to ensure that only one instance instance is created. Like the A Hungry man mode, it also utilizes the class loading mechanism, so there is no problem of multithreading concurrency. What's different is that it creates an object instance inside the inner class. In this way, as long as the internal class is not used in the application, the JVM will not be able to load the single instance class, nor will it create a single object, thus implementing lazy delay loading. In other words, this approach can guarantee both deferred loading and thread safety.

5, enumeration

Let's look at the last implementation that this article describes: enumerations.

Public enum singleton{
    instance;
    public void Whatevermethod () {}    
}

There are common drawbacks to the four implementations of the single example mentioned above:

1 requires additional work to implement serialization, otherwise a new instance is created each time a serialized object is deserialized.

2 You can use reflection to force a private constructor to be invoked (if you want to avoid this, you can modify the constructor so that it throws an exception when the second instance is created).

The enumeration class solves both of these problems by providing an automatic serialization mechanism to prevent the creation of new objects when deserializing, in addition to thread safety and the prevention of reflection call constructors. Therefore, the method that the author of the effective Java recommends to use. However, in practical work, it is rarely seen to be written in this way.


Summary

This article summarizes five kinds of Java implementation of a single example, the first two are not perfect, double check lock and static internal classes can solve most of the problems, peacetime work is used most of these two ways. Although the enumeration method solves all sorts of problems perfectly, but this kind of writing how many people feel unfamiliar. Personal advice is to implement a single case pattern using a third and a fourth way without special needs.


Reference article: Http://www.jfox.info/java-dan-li-mo-shi-de-ji-zhong-xie-fa

http://devbean.blog.51cto.com/448512/203501/

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.