The volatile Java Learning

Source: Internet
Author: User
Tags object object visibility volatile

Reprint: http://lucumt.info/posts/java-concurrency/java-volatile-keyword/

The Java keyword is volatile used to mark a Java variable to be stored in the main , more accurately interpreted as: each time a variable is read volatile from the computer's main memory read instead of the CPU cache read, each time a volatile variable is written, will be written to the main memory instead of being written to the CPU cache.

In fact, after Java5, the volatile keyword is not only used to ensure that the volatile variable is written to main memory and read from main memory, I will explain in detail in the following chapters:

Volatile Variable Visibility Guarantee

The Java volatile keyword ensures that volatile changes to variables are visible in multiple threads. This sounds a bit abstract, and I'll explain in detail next.

In a volatile multithreaded application that operates on non-variables, because of the performance relationship, each thread may copy variables from the main thread to the CPU cache when reading and writing these variables. If your computer has more than one CPU, each thread may run on a different CPU. This means that each thread may copy the variable to a different CPU's CPU cache, as shown in:
For volatile variables, the Java Virtual Machine (JVM) does not ensure when data is read from main memory to the CPU cache and when the CPU-cached data is written to main memory. And this may cause some problems that I will explain later.

Assume that two or more threads have access to the following shared variable that contains a counter:

public class SharedObject {    public int counter = 0;}

Again, only Thread1 increases the value of the counter variable, but both Thread1 and Thread2 can read the value of the counter variable at any time.

If the couner variable is not declared, it is volatile not guaranteed when the value in the CPU cache is written to main memory. This means that the value of the counter variable in the CPU cache may not be the same as the value in main memory, as follows:

Causes the thread to not get the variable the latest worthwhile reason is that the variable value is not written back to main memory by other threads in time, which is called visibility issues. Updates to one thread are not visible to other threads.

After the counter variable is declared volatile , all writes to the counter variable are immediately written to the main memory, and all read operations to the counter variable read the data from the main memory. The following code block shows how to declare a counter variable as volatile :

public class SharedObject {    public volatile int counter = 0;}

Therefore, defining a volatile variable guarantees that the operation of the write variable is visible to other threads.

The principle of volatile antecedent occurrence

The keyword is volatile not only used to ensure that variables are read and written from main memory after Java5, in fact, the keyword volatile has the following effect:

    • If thread A writes a volatile variable and then thread B reads the same volatile variable, all the variables that are visible to it before threads A is written volatile will be visible to it after reading it.
    • volatileRead and write instructions for variables cannot be reordered by the JVM (for performance reasons, the JVM may reorder instructions if the JVM detects that the ordering of instructions does not change the program's operation). The instructions before and after can be reordered, but volatile the read and write of variables cannot be mixed with these reordering instructions. Any instructions following the volatile read and write of a variable will ensure that it is executed only after the read and write operation of the variable.

The above explanation requires a further explanation.

When a thread writes to a volatile variable, not only does the volatile variable itself write to the main memory, but all variables that are affected by the variable are written to the main volatile memory. When a thread reads to a volatile variable, it also reads from main memory all variables that are written to the primary volatile memory along with the variable.

Take a look at the following example:

Thread A:    123;    sharedObject.counter     = sharedObject.counter + 1;Thread B:    int counter     = sharedObject.counter;    int nonVolatile = sharedObject.nonVolatile;

Because thread a writes a volatile non-variable sharedobject.nonvolatile before the write operation variable sharedobject.counter volatile , so when thread A writes the action variable After Sharedobject.counter , the variables sharedobject.nonvolatile and sharedobject.counter are written to main memory.

Since thread B starts with reading the volatile variable sharedobject.counter , the variable sharedobject.counter and the variable The Sharedobject.nonvolatile will be written to the CPU cache used by thread B. When thread B reads the sharedobject.nonvolatile variable, it will be able to see the variable written by thread A.

Developers can take advantage of the visibility of this extension to optimize the visibility of variables between threads. Unlike having each variable set to volatile , only a few variables need to be declared volatile . The following is a simple example program written with this rule Exchanger :

PublicClassExchanger {Private Object object =NullPrivateVolatile hasnewobject =FALSE; public void put (Object newObject) {while ( Hasnewobject) {//waits, does not overwrite new objects that already exist} object = NewObject; hasnewobject = true; //volatile Write} public Object take () {while (!hasnewobject) {//volatile read //waits, does not get the old object (or null object)} object obj = object; Hasnewobject = FALSE; //volatile write return obj;}      

Thread A May at any time increase the object by calling the put () method, and thread B May at any time get the object by calling the Take () method. As long as thread A only calls put () and thread B only calls take () , the Exchanger can work with a volatile variable (excluding synchronized the use of code blocks).

However, the JVM may reorder Java directives to optimize performance if the JVM can implement this functionality by not altering the semantics of these reordering instructions. What happens if the JVM swaps the read and write instructions in put () and take () ? What happens if the put () is actually executed like this?

while(hasNewObject) {    //等待,不覆盖已经存在的新对象}hasNewObject = true; //volatile写入object = newObject;

Note that volatile the write operation for the variable hasnewobject will be executed before the new variable is actually set, which may appear to be perfectly legal for the JVM. The value of the two write operations instruction is no longer dependent on the other.

However, the execution of command reordering may compromise the visibility of the object variable. First, thread B may read the value of Hasnewobject to True before it writes a value to object that is true to object . Second, there is no guarantee that when the new value of the object will be written to the main memory (well, the next time thread a writes the variable elsewhere ...) volatile

To prevent this from happening, the volatile keyword provides an antecedent principle. The antecedent guarantee ensures that volatile read and write instructions for variables are not reordered. Instructions may be reordered before and after the program is run, but the volatile read-write instruction cannot be reordered with any instructions before or after it.

Take a look at the following example:

123;sharedObject.nonVolatile2 = 456;sharedObject.nonVolatile3 = 789;sharedObject.volatile     = true; //a volatile variableint someValue1 = sharedObject.nonVolatile4;int someValue2 = sharedObject.nonVolatile5;int someValue3 = sharedObject.nonVolatile6;

The JVM may reorder the first 3 instructions, as long as they all occur before the volatile write instruction (they must all be volatile executed before the write instruction).

Similarly, the JVM may reorder the last 3 instructions, as long as the volatile write instruction precedes them, and none of the 3 instructions can be reordered to volatile the front of the instruction.

This is volatile the basic meaning of the principle of antecedent occurrence.

Volatile is not everything.

Although the volatile keyword ensures that all volatile read operations for variables are read directly from the main memory, all volatile writes to the variable are written directly to the master memory, but there are still some cases where defining only one volatile variable is not enough.

In the previous scenario, thread 1 writes to the shared variable counter , declaring that the counter variable is followed to volatile ensure that thread 2 always sees the most recent write value.

In fact, if the value written to the variable does not depend on the value preceding it, multiple threads can even hold the volatile correct value stored in main memory while writing to a shared variable. In other words, if a thread writes a volatile shared variable, it does not need to read the value of the variable first to calculate the next value.

Once a thread needs to read the value of a volatile variable first, and then generates the volatile next value of the shared variable based on that value, the volatile variable will no longer be able to fully ensure the correct visibility. In a volatile short interval of time between reading a variable and writing its new value, a race condition arises: multiple threads may read the volatile same value of the variable, then generate a new value and write to the main memory, which will overwrite each other's values.

This scenario where multiple threads increase the same counter at the same time is volatile where the variable is not applicable, and the next section is explained in more detail.

Suppose thread 1 reads a shared variable with a value of 0 counter to its CPU cache, adds 1 to it but does not write the added value to main memory. Thread 2 May read the same counter variable from main memory, with a value of 0, and not write it into primary memory, as shown in the following picture:

Thread 1 and thread 2 are not synchronized now, the true value of the shared variable counter should be 2, but in each thread's CPU cache, the value is 1, and the value in main memory is still 0. It's a mess, even if these threads finally write the computed value of the shared variable counter to main memory, the value ofcounter is still wrong.

Application Scenarios of volatile

As mentioned earlier, if two threads read and write to a shared variable at the same time, it volatile is not enough to use only variables. In this case, you need to use it synchronized to make sure that the read and write about the variable are atomic operations. Reading or writing a volatile variable does not block other threads from reading and writing the variable. In this case, you must use keywords synchronzied to decorate your critical code.

In addition to using synchronzied , you can also use some of the atomic data types in the Java.util.concurrent package, such as Atomiclong, Atomicreference, and so on.

When only one thread reads volatile and writes a variable and other threads read only that variable, volatile you can ensure that the read thread reads the most recent write value of the variable. If the variable is not declared volatile , then these read threads cannot guarantee that the read is the most recent write value.

VolatileKeywords apply to 32-bit variables and 64-bit variables.

Volatile performance considerations

Since volatile both the read and write of variables are directly from the main memory, it is more expensive to read and write directly to the main memory relative to the CPU cache, and access to a volatile variable also prevents instructions from reordering, and instruction sequencing is a common performance enhancement technique. Therefore, you should use variables only when you really need to ensure the visibility of variables volatile

The volatile Java Learning

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.