Patterns in Java--a single state-multithreading approach (partial translation double-checked locking break)

Source: Internet
Author: User
Tags garbage collection volatile
patterns in Java--single state (partial translation double-checked locking break)

Single State definition:
The main purpose of Singleton mode is to ensure that only one instance of a class classes exists in a Java application.

The singleton model provides us with the possibility of this implementation. The advantage of using singleton is that it can save memory because it limits
The number of instances is useful for Java garbage collection (garbage collection).

Use singleton considerations:
Sometimes in some cases, the use of Singleton does not achieve the purpose of Singleton, such as having multiple singleton objects that are simultaneously different classes
Loader loading; This is also noted for use in distributed systems such as EJBS, because EJB is a cross server that spans the JVM's

Evolution of a single State pattern:
A single state pattern is a simple pattern, but there are a lot of complex things about this simple pattern.

First, the simplest single state mode, the single state mode 1
Import java.util.*;
Class Singleton
{
private static Singleton instance;
Private Vector V;
Private Boolean inUse;

Private Singleton ()
{
v = new Vector ();
V.addelement (New Object ());
InUse = true;
}

  public static Singleton getinstance ()
  {
    if (instance = null)           //1
      instance = new Singleton (); / /2
    return instance;               //3
 }
}
This single state mode is unsafe, why do you say it? Because multithreading is not considered,
Thread 1 invokes the getinstance () method and determines that instance is null and enters the IF module,
before instantiating instance,
Thread 2 preempted thread 1 of the CPU
Thread 2 invokes the getinstance () method and determines that the instance is null and then enters the If module,
Thread 2 instantiates instance complete, and returns
Thread 1 Instantiate instance again
This single state is no longer a single State

Two, in order to solve the problem just now: Single State mode 2
public static synchronized Singleton getinstance ()
{
if (instance = null)//1
Instance = new Singleton (); 2
return instance; 3
}
It solves the problem by using synchronization, but the careful analysis
In normal circumstances, only the first time, into the object of the instantiation, need to sync,
The other time is to return directly to the instantiated good instance do not need to sync,
We all know that in a multithreaded program, if the synchronization of the consumption is very large, it is easy to create bottlenecks

Third, in order to solve the problem above: Single state mode 3, join synchronization
public static Singleton getinstance ()
{
if (instance = null)
{
Synchronized (Singleton.class) {
Instance = new Singleton ();
}
}
return instance;
}
Synchronized to block synchronization instead of using function synchronization, but with careful analysis,
It's back to the state of mode one, and there's no problem at all when it comes to multiple threads.

Four, in order to correspond to the above question: the single State mode 4, also is many people uses the double-checked locking
public static Singleton getinstance ()
{
if (instance = null)
{
Synchronized (singleton.class) {//1
if (instance = null)//2
Instance = new Singleton (); 3
}
}
return instance;
}
In this way, the problem mentioned in pattern one is solved. No occurrences of multiple instantiations
When the first entry, a positive instantiation of the single State, after the instantiation, multi-threaded access when the direct return, do not need to enter the synchronization module,
Both the single State and the loss of performance are achieved. On the surface, we solved the problem, but then we analyzed it carefully:
Let's pretend this is the case:
Thread 1: Go to the//3 location, execute the new Singleton (), but be Thread2 to preempt the CPU at the start of the constructor
Thread 2: Enter getinstance (), judge instance not equal to NULL, return instance,
(instance has already been allocated memory space, but no initialization data)
Thread 2: Use the returned instance to do certain exercises, failures or anomalies
Thread 1: Get CPU initialization complete
There may be multiple threads in the process that have not completed the instance, and use this instance to make certain exercises.
-----------------------------------------
The above problem arises because
MEM = allocate (); Allocating memory
instance = mem; Mark Instance not empty
constructor not executed, thread 2 enters from here
Ctorsingleton (instance); Executing constructors
Back to instance
------------------------------------------

Five, to prove that the above hypothesis is possible, bytecode is used to analyze the problem of the best tool, you can use it to analyze
The following procedure: (in order to analyze the convenience, so gradually less content)
How to use byte code here, using bytecode to analyze problems
Class Singleton
{
private static Singleton instance;
Private Boolean inUse;
private int val;

Private Singleton ()
{
InUse = true;
val = 5;
}
public static Singleton getinstance ()
{
if (instance = null)
Instance = new Singleton ();
return instance;
}
}
The resulting byte code
; ASM code generated for getinstance
054D20B0 mov eax,[049388c8]; load instance ref
054D20B5 test eax,eax; test for NULL
054d20b7 jne 054d20d7
054D20B9 mov eax,14c0988h
054D20BE call 503ef8f0; allocate memory
054D20C3 mov [049388c8],eax; store pointer in
; instance Ref. instance
; Non-null and ctor
; Has not run
054D20C8 mov ecx,dword ptr [eax]
054D20CA mov dword ptr [ecx],1; inline ctor-inuse=true;
054D20D0 mov dword ptr [ecx+4],5; inline ctor-val=5;
054D20D7 mov ebx,dword ptr ds:[49388c8h]
054D20DD jmp 054d20b0

The byte code above proves that conjecture is possible.

VI: Well, it is proved that double-checked locking may be out of error data, then we can still solve
public static Singleton getinstance ()
{
if (instance = null)
{
Synchronized (singleton.class) {//1
Singleton Inst = instance; 2
if (inst = null)
{
Synchronized (singleton.class) {//3
Inst = new Singleton (); 4
}
instance = Inst; 5
}
}
}
return instance;
}
Using double-checked locking two times synchronization, intermediate variables to solve the above problems.
(The bottom of this paragraph I can only simple understanding, translation is not good, so keep the original, List 7 is the top of the code, List 8 is the bottom of the
The code in Listing 7 doesn ' t work because of the current definition of the memory model.
The Java Language specification (JLS) demands that code within a synchronized block
Not is moved out of the a synchronized block. However, it does not say that
The code not in a synchronized block cannot to moved into the a synchronized block.
A JIT compiler would to optimization opportunity here.
This optimization would remove the code at
4 and the code at//5, combine it and generate the code shown in Listing 8:)
-------------------------------------------------
List 8
public static Singleton getinstance ()
{
if (instance = null)
{
Synchronized (singleton.class) {//1
Singleton Inst = instance; 2
if (inst = null)
{
Synchronized (singleton.class) {//3
Inst = new Singleton (); 4
Instance = new Singleton ();
}
instance = Inst; 5
}
}
}
return instance;
}
If This is optimization takes place, you have the same out-of-order write problem we discussed earlier.
If this optimization occurs, the problem mentioned above will occur again, and the data that has not been instantiated is obtained.
-------------------------------------------------

The following sections in order to avoid my translation error misleading dozen home, retaining the original

Another idea are to use the keyword volatile for the variables inst and instance.
According to the JLS (in), variables declared volatile are to
Be sequentially consistent, and therefore, not reordered.
But two problems occur with trying to use volatile to fix the problem with
double-checked Locking:

The problem is sequential consistency.
The Code is being moved and not reordered.

Many JVMs does not implement volatile correctly regarding sequential.
The second point is worth expanding upon. Consider the code in Listing 9:

Listing 9. Sequential consistency with volatile

Class Test
{
Private volatile Boolean stop = false;
private volatile int num = 0;

public void Foo ()
{
num = 100; This can happen second
Stop = true; This can happen a
//...
}

  public void Bar ()
  {
    if (stop)
      num + + num;& nbsp num can = = 0!
 }
 /...
}
 
According to the JLS, because stop and NUM are declared,
volatile they is should sequentially Stent. This means the IF stop is ever true, the
Num must have been set to 100.
However, because many JVMs don't implement the sequential consistency feature of volatile,
you cannot count on thi s behavior.
Therefore, if thread 1 called foo and thread 2 called Bar concurrently,
Thread 1 might set stop to true before Num is set to 100.
This could leads thread 2 to the But Num still set to 0.
There are additional problems with volatile and the atomicity of 64-bit variables,
But this is beyond the scope of This article.
information on this topic.

A simple understanding of the above paragraph, the use of volatile may be able to solve the problem, volatile is defined to guarantee positive consistency, but many virtual machines
Does not have the very good realization volatile, therefore uses it also to have the question.

The Final Solution:
(1), single State mode 2, using the synchronization method
(2), discard synchronization, use a static variable, as follows
Class Singleton
{
Private Vector V;
Private Boolean inUse;
private static Singleton instance = new Singleton ();

Private Singleton ()
{
v = new Vector ();
InUse = true;
//...
}

public static Singleton getinstance ()
{
return instance;
}
}
But there are also problems with static variables, see this article

And, as mentioned at the beginning of the article, using EJBS across servers, and across JVMs, a single state is a problem

Okay, is it a sense that a single state model is simply impossible to use, in fact, the above are special circumstances, the appearance of this special situation is conditional, as long as
According to your specific application, avoid some, can solve the problem, so the single State can still be used. But before you use it carefully, think about yourself.
The situation is suitable for which situation.

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.