A detailed description of the volatile

Source: Internet
Author: User
Tags visibility volatile

The volatile keyword-Modified shared variable has two main features: 1. Memory visibility for different thread access 2. Prevent reordering

Before we talk about memory visibility and ordering, we need to look at the memory model of Java (note the distinction between the JVM memory model)

Why do you have a Java memory model?

First we know that memory access and CPU instructions in the execution speed difference is very large, not a magnitude, in order to make Java on each platform to run the gap, which processors of the big guy on the CPU added a variety of cache, to reduce memory operation and CPU instruction execution speed gap. Java at the Java level and another wave of abstraction, the Java memory model divides the memory into working memory and main memory, each thread from the main storage load data to the work, the load data to the working memory variables, and then the working memory corresponding thread for processing, The processing results are assigned to their working memory, and then the data is assigned to the variables in main memory (a graph is required at this time).

The use of working memory and main storage speed up the processing speed, but also brings some problems, such as the following example

1         int i = 1; 2         i = i+1;

When a single-threaded case, the last value of I must be 2, but in two threads it must be 3? That's not necessarily the same. When thread a reads I with a value of 1,load to its working memory, then the CPU switches to thread B, thread B reads I's value is also 1, then adds 1 and then save to main memory, then thread A also adds 1 to I and save back to main memory, but finally I has a value of 2. If the write operation is slow, the value you read may also be 1, which is the problem of cache inconsistency. JMM is built around the three characteristics of atomicity, memory visibility, and ordering. Solve the problem of cache inconsistency by solving this three feature. Volatile is primarily for memory visibility and ordering.

Atomic Nature

Atomicity refers to an operation is either successful, then failed, no intermediate state, such as I=1, directly read the value of I, which is definitely atomic operation, but i++, it seems like, actually need to read the value of I, and then +1, the last assignment to I, it takes three steps, this is not atomic operation. In JDK1.5, the Atomic class Atomicboolean, Atomiclong, and Atomicinteger, which correspond to Boolean, long, and int, are introduced, and they can provide atomic operations.

Memory visibility

variables with memory visibility are flushed to main memory immediately after being modified by the thread and invalidate data on other threads ' cache rows .

Volatile modified variables have memory visibility, mainly as follows: When a volatile variable is written, JMM will immediately flush the shared variable in the working memory corresponding to that thread to main memory; When a volatile variable is read, The JMM will set the value in the working memory of the thread to be invalid and then read from memory, but if no thread modifies the shared variable, the operation will not be triggered.

Order of

JMM allows the processor and compiler to reorder the instructions, but specifies the as-if-serial, that is, the final result is the same no matter how it is reordered. For example, the following code:

1         int weight = ten;                           // A 2         int high = 5;                                // B 3         int area = high * weight * high;    // C

This code can be executed in accordance with A-->B-->C, or can be executed according to B-->a-->c, because A and b are independent of each other, and C depends on a, B, so C can not be ranked in front of a or B. JMM guarantees a single-threaded reordering, but is prone to problems in multiple threads. such as the following situation

1 BooleanFlag =false;2     intA = 0;3     4      Public voidwrite () {5         intA = 2;//16Flag =true;//27     }8      Public voidMultiply () {9         if(flag) {//3Ten             intRET = A * A;//4 One         } A}

If there are two threads executing the above code, thread 1 executes the Write method first, and then thread 2 executes the multiply method. The final result must be 4, not necessarily.

, JMM 1 and 2 are reordered, the flag is set to True, which is thread 2 execution, because a has not been assigned, so the value of the last RET is 0;

If you use the volatile keyword to decorate flag, it is forbidden to reorder, you can guarantee the order of the program, you can also use the synchronized or lock of the heavyweight lock to ensure the order, but performance will be degraded.

In addition, JMM has some innate ordering , that is, the order that can be guaranteed without any means, often called the happens-before principle. <<JSR-133:Java Memory Model and Thread Specification>>The following happens-before rules are defined:

    1. program order rules : Every action in a thread, happens-before any subsequent action in that thread

    2. monitor Lock Rule : Unlocks a thread happens-before the subsequent locking of the thread

    3. volatile variable rule : writes to a volatile field, happens-before to subsequent reads of this volatile field

    4. transitivity : If a happens-before B, and B happens-before C, then a happens-before c

    5. start () Rule : If thread A performs an action Threadb_start () (boot thread B), then the Threadb_start () of a thread Happens-before Any action in B

    6. join () Principle : If a executes threadb.join () and returns successfully, Then any action in thread B happens-before the successful return of thread A from the threadb.join () operation.

    7. interrupt () Principle : The invocation of the thread interrupt () method occurs when the interrupted thread code detects that the interrupt event occurred and can be thread.interrupted () method detects if an interrupt occurred

    8. Finalize () Principle : Initialization of an object takes place in its Start of the Finalize () method

1th Rule Program Order rules is said in a thread, all operations are in order, but in jmm in fact, as long as the execution results, is allowed to reorder, this side of the Happens-before emphasis is the correctness of single-threaded execution results, but there is no guarantee that multithreading is the same.

The 2nd Rule Monitor rule is understood, that is, before the lock, it is determined that the lock has been released before the lock can continue.

The 3rd rule applies to the volatile discussed, if a thread first writes a variable and another thread reads it, the write must be before the read operation.

The 4th rule is the transitivity of Happens-before.

It is important to note that volatile-modified shared variables only satisfy memory visibility and prohibit reordering, and do not guarantee atomicity. such as volatile i++.

1  Public classTest {2      Public volatile intinc = 0;3  4      Public voidIncrease () {5Inc++;6     }7  8      Public Static voidMain (string[] args) {9         FinalTest test =NewTest ();Ten          for(inti=0;i<10;i++){ One             NewThread () { A                  Public voidrun () { -                      for(intj=0;j<1000;j++) - test.increase (); the                 }; - }.start (); -         } -   +          while(Thread.activecount () >1)//ensure that the previous threads are finished executing - Thread.yield (); + System.out.println (test.inc); A}

The result is 10000, but it is probably a value less than 10000 under operation. One might say that volatile is not guaranteed visibility ah, one thread to the change of INC, another thread should immediately see Ah! But here's the operation Inc++ is a compound operation Ah, including read the value of INC, to its self-increment, and then write back to main memory.

Assuming thread A, the value of an inc is read at 10, it is blocked because the variable is not modified and the volatile rule is not triggered.

Thread B also read Inc at this time, the value of Main Memory Inc is still 10, do self-increment, and then immediately be written back to main memory, 11.

Now it's time to thread a execution, because the working memory is 10, so continue to do self-increment, and then write back to main memory, 11 was written again. So while two threads executed two increase (), the result was only added once.

It is said thatvolatile does not invalidate the cache line ? But here thread a reads to thread B and does not modify the INC value, so when thread B reads, it still reads 10.

Others say that thread B writes 11 back to main memory, and does not set thread A's cache row to be invalid ? But the read operation of thread A has already done, ah, only when doing the read operation, found that the cache row is not valid, will read the main memory value, so here thread A can only continue to do self-increment.

To sum up, in this compound operation scenario, the atomic function is not maintained. However, volatile in the above example of setting the flag value, because the read/write operation of flag is a single step, it can still guarantee the atomicity.

To ensure atomicity, only by means of Synchronized,lock and the atomic Operation Class of the atomic under the concurrent package, that is, the self-increment of the basic data type (plus 1 operations), the self-subtraction (minus 1 operations), and the addition operation (plus one number), the subtraction operation (minus one number) is encapsulated, Ensure that these operations are atomic operations.

Volatile underlying principle

If you compile the code with the volatile adornment and the code that does not use the volatile adornment into assembly language, you will find that the code that uses the volatile adornment will have one more lock prefix directive.

The lock prefix directive is equivalent to a memory barrier, and the memory barrier serves the following three points:

When ① is reordered, the instructions behind the memory barrier cannot be sorted before the memory barrier

② causes the cache of this CPU to write to memory

③ write actions can cause other CPU caches or data in the kernel to be invalid, which is equivalent to the modification being visible to other threads.

Application Scenarios for volatile

Because volatile is not valid for compound operations, volatile modifies only the read/write marker fields such as flag in the example above.

In simple interest mode, volatile can also modify member variables to prevent command reordering at initialization time.

1 classsingleton{2     Private volatile StaticSingleton instance=NULL;3     4     PrivateSingleton () {5         6     }7     8      Public StaticSingleton getinstance () {9         if(instance==NULL){Ten             synchronized(Singleton.class){ One                 if(instance==NULL){ AInstance =NewSingleton (); -                 } -             } the         } -         returninstance; -     } -}

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.