Regarding the java volatile keyword, don't make it clear in the interview in the future

question

Code Listing 1

class SingleInstance{
    private static single = null;
    private SingeInstance(){}
    public SingleInstance getSingleInstance(){
        if(single == null)//0
            synchroznied(SingleInstance.class){
                if(single == null){
                    single = new SingleInstance();//1
                }
        }
        return single;
    }
}

The problem with the above code is that ordering cannot be guaranteed at 1, that is, this code is actually divided into two major steps

  • Initialize SingleInstance
  • Assign this object to the single variable

Before and after this step is uncertain. When the thread runs to 1, the object may be assigned to the single first, but the single has not been initialized at this time. When thread 2 runs at 0, it will find that this condition is not met, so it returns single. At this time, although the single is a non-null reference, it is not a correct object. This is a possible problem with double verification.

volatile

Maybe you have heard that modifying the variable single with volatile after JDK1.4 can solve this problem, but do you know why it can be solved?

The semantics of volatile is to maintain order and visibility , but not to guarantee atomicity

visibility

What is visibility?

by

count = 0;
couont++;

For example, the execution process of this line of code is as follows:

  1. Load the value of count from memory into its own thread stack
  2. Increment count in its own thread stack
  3. Put the modified value back into main memory.

in the case of multithreading

  • Thread 1 performed the first operation
  • After that, thread 2 also performs the first operation
  • Thread 1 performs the last two operations, and the count value in main memory becomes 1;
  • Thread 2 continues to perform the second operation, which uses its own copy of the stack to add 1 to the value of 0, and finally executes the third operation to write 1 back to main memory.

See the problem, it's still 1 after adding it twice, something happened, brother!

What is the role of volatile in it?

When the count is modified with volatile, when the thread performs the operation, that is, the above ****2 step , he will not take the value in the copy, but go to the main memory to take the value.

Even that doesn't solve the counting problem, why?

  • Thread 1 takes the value from the memory and adds 1, and the count value of the thread copy becomes 1.
  • Then thread 2 fetches the value from the main memory. At this time, the value fetched is 0. After adding 1, the write will go to the main memory, and the count in the main memory becomes 1.
  • Thread 1 performs step 3 to write the count value of 1 in its own copy back to the main memory, and the main memory is still 1.

summary

The visibility semantics of volatile is to ensure that the thread operates, that is, the above step 2 fetches the latest value from the main memory instead of fetching the value in its own copy.

orderliness

In the Java memory model, the compiler and processor are allowed to reorder instructions, but the reordering process will not affect the execution of single-threaded programs, but will affect the correctness of multi-threaded concurrent execution.

Example: Code Listing 2

线程A中
context = initContext();//1
flag = true;//2

线程B中
while(!flag){
  sleep(100);
}
dosomething(context);

There is no problem with the code in a single thread, but as in the code listing 2, the code of thread A may be reordered, that is, running code 2 and then running code 1, which is a problem.

If it is modified with volatile, it will prohibit him from reordering.

atomicity

Atomicity is simply indivisible. If it is an atomic operation, it must be either executed completely or not executed at all. It is impossible to execute a part of this situation.

Summarize

Volatile fields guarantee visibility and prohibit reordering, but do not provide atomicity. The reason is that under the condition of multi-threading, the execution order cannot be guaranteed, and there will be thread switching in the middle.

Back to Listing 1 Remember the original question? What's wrong with this singleton in Listing 1 has already been said. How to solve it? In fact, it is easy to solve the problem with the keyword volatile. Adding volatile to the single variable can solve it perfectly. The reason is that volatile has the ability to prohibit reordering. Therefore, the object will be initialized first and then assigned to the variable. When the single detected at 0 is not empty, the single can be returned correctly instead of an incomplete single.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325561588&siteId=291194637