Detailed volatile underlying principle

Will share their knowledge, the future will continue to export, we want to give the reader friends help. If readers can help point praise or attention.


JavaStorm.png

Today we talk about volatile underlying principle;

Java language specification for the volatile is defined as follows:

Java programming language allows threads to access shared variables, in order to ensure that shared variables can be accurately and consistently updated by thread should ensure exclusive lock to get this variable alone.

First, we start by defining the start, the official definition of a mouthful. Popular, is a volatile field is modified, Java memory model ensures that all threads see the value of this variable is the same, but it does not guarantee multithreaded atomic operations. This is called a thread visibility. We want to know that he can not guarantee atomicity .

Memory model concepts

Communications between threads is controlled by the Java Java memory model (JMM), JMM determines a modification to the shared variable thread when another thread is visible on. JMM defines an abstract relationship with the main thread of memory: In the main memory (Main Memory), each thread has a private local memory (Local Memory) holds a copy of the shared memory variables are variables between threads. JMM local memory is an abstract concept, and are not real.


If thread A and thread B Communication:

  1. A thread to be updated first local memory A shared variable flushed to main memory.

  2. Thread B read into main memory shared variables to update the thread A

When the computer running the program, each instruction is executed in the CPU during execution inevitably involve reading and writing data. We know that the data is stored program running in main memory, then there will be a problem, read and write data in main memory is not fast CPU to execute instructions, if any interaction is required to deal with the main memory will greatly affect the efficiency, so there is a CPU cache. CPU CPU cache for a unique, only with the thread running in the CPU.

With the CPU cache solves the problem of efficiency, but it will bring a new problem: data consistency. The program is running, will copy the data needed to run to a CPU cache, main memory CPU no longer have to deal with during operation, but read and write data directly from the cache only when the end of the run after data will be flushed to main memory.

for example:

i++;

When a thread to execute this command, it reads from the main memory i, and then copy the cache to the CPU, then the CPU performs +1, +1 and then write the data in the cache, the final step It is flushed to main memory. There is no problem in the single-threaded, multi-threaded have a problem.

As follows: if there are two threads A, B perform the operations (i ++), the value of i according to our normal logical thinking main memory should = 3, but the fact is that it?

analyse as below:

Two threads read from the main memory the value of i (1) to the respective cache, and thread A executes +1 and the results written into the cache, the main memory last written in the main memory at this time i == 2, B thread to do the same operation, main memory is still i = 2. So the final result is 2 not 3. This phenomenon is the cache coherency problem.

There are two solutions to solve the cache coherence:

  1. By adding LOCK # bus lock mode;

  2. Through cache coherency protocol.

But there is a problem Scenario 1, it is to adopt a exclusive way to achieve, namely a bus-LOCK # lock, then only one CPU can run other CPU had blocked more efficiency is low.

The second option, cache coherency protocol (MESI protocol) it ensures that each copy of the shared variable used in the cache is the same. So JMM to solve this problem.

The principle volatile

When there are volatile modified shared variable write operation will be more Lock prefix instructions in multi-core processors will lead to two things.

  1. The current processor cache line of data flushed to main system memory.

  2. The data flashed back to main memory handling can lead to other CPU cache memory address of the shared variable is invalid.

This ensures that the cache is consistent with the plurality of processors, the processor corresponding to the cache line corresponding to find their own memory address is modified, will be provided of the current processor cache line invalid state, when the processor of the data modification operations when will re-read the data from main memory into the cache.

scenes to be used

volatile often used in two scenarios: the condition mark, double check

  1. State flag
//线程1
boolean stop = false;
while(!stop){
   doSomething();
}

//线程2
stop = true;
复制代码

This code is very typical piece of code, a lot of people probably will adopt this approach in the mark interrupt thread. But in fact, this code will run entirely correct it? That will certainly thread interrupts it? Not necessarily, maybe most of the time, this code can interrupt the thread, but also may lead to not interrupt thread (although this is unlikely, but just once this happens it will cause a cycle of death).

Here to explain why this code may lead to not interrupt thread. I have already explained, during operation each thread has its own working memory, so when the thread 1 is running, the value of a variable copy will stop working on his memory of them.

So when Thread 2 change the value of the variable stop, but not enough time to write main memory among threads 2 turn to do other things, then thread 1 because they do not know to change the thread stop two pairs of variables, and therefore also been circulating down.

But with volatile no problem. As follows:

    volatile boolean flag = false;

    while(!flag){
       doSomething();
    }

    public void setFlag() {
       flag = true;
    }

    volatile boolean inited = false;
    //线程1:
    context = loadContext();  
    inited = true;            

    //线程2:
    while(!inited ){
    sleep()
    }
    doSomethingwithconfig(context);
复制代码
  1. double check
public class Singleton{
   private volatile static Singleton instance = null;

   private Singleton() {

  }

   public static Singleton getInstance() {
       if(instance==null) {
           synchronized (Singleton.class) {
               if(instance==null)
                   instance = new Singleton();
          }
      }
       return instance;
  }
}
复制代码

Keguan find it useful please praise or collection, public concern number JavaStorm, you will find an interesting soul!
Later we continue to analyze the JMM memory model related technologies.


Guess you like

Origin juejin.im/post/5cee2aee6fb9a07ed2245038