Multi-threaded single-case model: lazy loading (lazy loading) and real-time load

 

In development, if you create an instance of the need to consume a lot of system resources, so we usually use lazy loading mechanism, that will only create an instance of when to use this example when the benefits obtained in singleton mode a wide range of applications. This mechanism is very simple in the realization of a single-threaded environment, however, there are risks in the multi-threaded environment. This article focuses on inertia loading mechanism and its use in a multithreaded environment. (Author numberzero, refer to IBM article "Double-checked locking and the Singleton pattern", welcome to reprint and discussion)

1, an inert singletons loading
Normally when we designed a singleton class, will construct the class (the constructor, or created directly defined at) within the class, and outside a static getInstance method of providing access to the ways singleton object. E.g:

Copy the code
Copy the code
public class Singleton        
{        
    private static Singleton instance = new Singleton();        
    private Singleton(){        
    }        
    public static Singleton getInstance(){        
             return instance;         
    }        
} 
Copy the code
Copy the code

The disadvantage is that this code: When first loaded class will be created even with Singleton instance, such a result and we expect different because create an instance when we might not need this instance the time. And if this created Singleton instance consuming system resources, and the application did not always use the Singleton instance, the creation of system resources consumed by Singleton was wasted.

To avoid this, we usually use the lazy loading mechanism, which is only going to create when in use. Lazy loading the code of the code above is as follows:

Copy the code
Copy the code
public class Singleton{        
    private static Singleton instance = null;        
    private Singleton(){        
    }        
    public static Singleton getInstance(){        
        if (instance == null)        
            instance = new Singleton();         
                return instance;         
    }        
}       
Copy the code
Copy the code

2, lazy loading multithreading problems
first code loaded inert extracted:   

public static Singleton getInstance(){        
    if (instance == null)        
    instance = new Singleton();         
    return instance;         
}      

 That is, if two threads A and B at the same time the method has executed, and then performed in the following manner:

1. A judgment entered if, when foo is null, if so into the

2. B determines if entered, then A has not been created foo, so foo is also null, and therefore if B also enters the

3. A creates a Foo and returns

4. B also creates a Foo and returns

At this point the question arises, our singleton is created twice, which is not what we expected.

3 solutions and its problems
3.1 Class locking mechanism
of the above problems most intuitive solution is to add a method to synchronize getInstance prefix, which allows only one ready to call getInstance method:

public static synchronized Singleton getInstance(){        
    if (instance == null)        
    instance = new Singleton();         
    return instance;         
}       

    Such a solution can indeed prevent the occurrence of the error, but it is very affecting performance: each call to getInstance method when Singleton must obtain a lock, in fact, after a single case when the instance is created, the subsequent request is not necessary then use a mutual exclusion mechanism

3.2 double-checked locking
Someone once to solve the above problem, double-checked locking solutions

Copy the code
Copy the code
public static Singleton getInstance(){        
    if (instance == null)        
        synchronized(instance){        
            if(instance == null)        
                instance = new Singleton();        
        }        
    return instance;         
} 
Copy the code
Copy the code

 Let's look at how this code works: First, when a thread makes a request, it will first check whether the instance is null, if not directly then return to its contents, thus avoiding resource into the synchronized block it takes. Secondly, even if mentioned in section 2 occurs, two threads into the first if a judge, then they must also perform synchronized block of code in the order, the first thread block of code creates a new entry the Singleton instance, and subsequent threads are because they can not pass judgment if, without creating extra instances.

         The above description seems to have solved all our problems, but in fact, from the JVM's point of view, the code still errors may occur.

         For the JVM, it performs is one Java instructions. Creating objects and assignment operator in Java instructions are carried out separately, that instance = new Singleton (); statement is executed in two steps. But the JVM does not guarantee the order of these two operations, which means that there may be a new JVM instance Singleton allocate space, then directly assigned instance member, then go to initialize the Singleton instance. This will make mistakes as possible, we still A, B two threads, for example:

1. A, B threads into the first determining if a

2. A first enters the synchronized block, since the instance is null, it performs instance = new Singleton ();

3. Since the optimization mechanism inside the JVM, the JVM number assigned to a first draw blank memory Singleton instance, and assigned to the member instance (note that this case does not start initialization JVM this example), and then left A synchronized block.

4. B enters the synchronized block, since this time instance is not null, it immediately left the synchronized block and returns the result to the program that called the method.

5. At this time, the thread B Singleton instance intended use, but found that it is not initialized, then an error has occurred.

Singleton in a multithreaded environment is achieved through an internal 4 class
in order to achieve slow to load, and do not want to have to be mutually exclusive execution every time getInstance call, the best and most convenient solution is as follows:

Copy the code
Copy the code
public class Singleton{        
    private Singleton(){        
    }        
    private static class SingletonContainer{        
        private static Singleton instance = new Singleton();        
    }        
    public static Singleton getInstance(){        
        return SingletonContainer.instance;        
    }        
}   
Copy the code
Copy the code

     The JVM internal mechanism to ensure that when a class is loaded, the loading process of this class is the thread mutually exclusive. So that when we first call the getInstance, JVM can help us ensure that instance is created only once, and will ensure that the memory assigned to the instance initialized, so we do not worry about the 3.2. In addition, the method will only use mutual exclusion mechanism at the time of the first call, this would resolve the inefficiencies of 3.1. The last instance is created when you first load SingletonContainer class, and SingletonContainer class is only loaded when invoking getInstance method, and therefore achieve a lazy loading.

In development, if you create an instance of the need to consume a lot of system resources, so we usually use lazy loading mechanism, that will only create an instance of when to use this example when the benefits obtained in singleton mode a wide range of applications. This mechanism is very simple in the realization of a single-threaded environment, however, there are risks in the multi-threaded environment. This article focuses on inertia loading mechanism and its use in a multithreaded environment. (Author numberzero, refer to IBM article "Double-checked locking and the Singleton pattern", welcome to reprint and discussion)

1, an inert singletons loading
Normally when we designed a singleton class, will construct the class (the constructor, or created directly defined at) within the class, and outside a static getInstance method of providing access to the ways singleton object. E.g:

Copy the code
Copy the code
public class Singleton        
{        
    private static Singleton instance = new Singleton();        
    private Singleton(){        
    }        
    public static Singleton getInstance(){        
             return instance;         
    }        
} 
Copy the code
Copy the code

The disadvantage is that this code: When first loaded class will be created even with Singleton instance, such a result and we expect different because create an instance when we might not need this instance the time. And if this created Singleton instance consuming system resources, and the application did not always use the Singleton instance, the creation of system resources consumed by Singleton was wasted.

To avoid this, we usually use the lazy loading mechanism, which is only going to create when in use. Lazy loading the code of the code above is as follows:

Copy the code
Copy the code
public class Singleton{        
    private static Singleton instance = null;        
    private Singleton(){        
    }        
    public static Singleton getInstance(){        
        if (instance == null)        
            instance = new Singleton();         
                return instance;         
    }        
}       
Copy the code
Copy the code

2, lazy loading multithreading problems
first code loaded inert extracted:   

public static Singleton getInstance(){        
    if (instance == null)        
    instance = new Singleton();         
    return instance;         
}      

 That is, if two threads A and B at the same time the method has executed, and then performed in the following manner:

1. A judgment entered if, when foo is null, if so into the

2. B determines if entered, then A has not been created foo, so foo is also null, and therefore if B also enters the

3. A creates a Foo and returns

4. B also creates a Foo and returns

At this point the question arises, our singleton is created twice, which is not what we expected.

3 solutions and its problems
3.1 Class locking mechanism
of the above problems most intuitive solution is to add a method to synchronize getInstance prefix, which allows only one ready to call getInstance method:

public static synchronized Singleton getInstance(){        
    if (instance == null)        
    instance = new Singleton();         
    return instance;         
}       

    Such a solution can indeed prevent the occurrence of the error, but it is very affecting performance: each call to getInstance method when Singleton must obtain a lock, in fact, after a single case when the instance is created, the subsequent request is not necessary then use a mutual exclusion mechanism

3.2 double-checked locking
Someone once to solve the above problem, double-checked locking solutions

Copy the code
Copy the code
public static Singleton getInstance(){        
    if (instance == null)        
        synchronized(instance){        
            if(instance == null)        
                instance = new Singleton();        
        }        
    return instance;         
} 
Copy the code
Copy the code

 Let's look at how this code works: First, when a thread makes a request, it will first check whether the instance is null, if not directly then return to its contents, thus avoiding resource into the synchronized block it takes. Secondly, even if mentioned in section 2 occurs, two threads into the first if a judge, then they must also perform synchronized block of code in the order, the first thread block of code creates a new entry the Singleton instance, and subsequent threads are because they can not pass judgment if, without creating extra instances.

         The above description seems to have solved all our problems, but in fact, from the JVM's point of view, the code still errors may occur.

         For the JVM, it performs is one Java instructions. Creating objects and assignment operator in Java instructions are carried out separately, that instance = new Singleton (); statement is executed in two steps. But the JVM does not guarantee the order of these two operations, which means that there may be a new JVM instance Singleton allocate space, then directly assigned instance member, then go to initialize the Singleton instance. This will make mistakes as possible, we still A, B two threads, for example:

1. A, B threads into the first determining if a

2. A first enters the synchronized block, since the instance is null, it performs instance = new Singleton ();

3. Since the optimization mechanism inside the JVM, the JVM number assigned to a first draw blank memory Singleton instance, and assigned to the member instance (note that this case does not start initialization JVM this example), and then left A synchronized block.

4. B enters the synchronized block, since this time instance is not null, it immediately left the synchronized block and returns the result to the program that called the method.

5. At this time, the thread B Singleton instance intended use, but found that it is not initialized, then an error has occurred.

Singleton in a multithreaded environment is achieved through an internal 4 class
in order to achieve slow to load, and do not want to have to be mutually exclusive execution every time getInstance call, the best and most convenient solution is as follows:

Copy the code
Copy the code
public class Singleton{        
    private Singleton(){        
    }        
    private static class SingletonContainer{        
        private static Singleton instance = new Singleton();        
    }        
    public static Singleton getInstance(){        
        return SingletonContainer.instance;        
    }        
}   
Copy the code
Copy the code

     The JVM internal mechanism to ensure that when a class is loaded, the loading process of this class is the thread mutually exclusive. So that when we first call the getInstance, JVM can help us ensure that instance is created only once, and will ensure that the memory assigned to the instance initialized, so we do not worry about the 3.2. In addition, the method will only use mutual exclusion mechanism at the time of the first call, this would resolve the inefficiencies of 3.1. The last instance is created when you first load SingletonContainer class, and SingletonContainer class is only loaded when invoking getInstance method, and therefore achieve a lazy loading.

Guess you like

Origin www.cnblogs.com/zyy1688/p/11077142.html