Java volatile keyword Full explanation-attached example

Source: Internet
Author: User
Tags volatile

Java volitile Key Words

The Java volatile keyword is used to mark a Java variable as "stored in main memory". More precisely, each read operation against a volatile variable reads from the main memory rather than from the CPU's cache, and each write to the volatile variable is written to the main memory, not just to the CPU cache.

In fact, starting with Java 5, the volatile keyword guarantees something else in addition to reading and writing volatile variables from the main memory. I'll explain it in a later section.

Variable Visibility Issues

The Java volatile keyword guarantees the visibility of variable value changes across multiple threads. This description is somewhat abstract, so let me explain it in detail.

In a multithreaded program, if a thread operates on some non-volatile variable, each thread may replicate the variable value from main memory to the CPU cache in order to improve performance. If your computer has more CPUs than one, different threads may run on different CPUs. This means that different threads may copy variables into the cache of different CPUs:

For variables that use non-volatile, the Java Virtual Machine (JVM) will not guarantee when the data is read from the main memory to the CPU cache, nor does it guarantee when the CPU cache data is written back to main memory. This will cause some problems. I'll explain it in detail later.

Imagine that two or more than two threads can access a shared object that contains a single counter:

Imagine that only thread 1 increases the counter variable, but thread 1 and thread 2 will read the counter variable from time to moment.

If the counter variable is not declared as a volatile,counter variable, the value will not be guaranteed to be written back to the main memory from the CPU cache. This means that the value of the counter variable in the CPU cache may not be the same as the value in main memory. This situation:

Because a thread has not written the value of the variable back to main memory, the problem that other threads cannot read to the most recent value of this variable is known as the "visibility" issue. Changes to one thread are not visible to other threads.

Java volatile Visibility Guarantee

The goal of the Java volatile keyword is to solve the problem of visibility of variables. A volatile counter variable is declared, and all writes to counter will understand that it is written back to main memory. All read operations to the counter variable are also read from the main memory.

The following is a statement with the volatile counter:

Declaring a variable to be volatile can thus guarantee the visibility of other threads ' write operations to that variable.

In the above scenario, one thread (thread 1) modifies counter, and another thread (thread 2) reads counter (but never modifies it), declaring that the counter variable is volatile enough to guarantee the visibility of thread 2 for write operations against counter variables.

However, if thread 1 and thread 2 both modify the value of counter, it is not sufficient to simply declare that the counter variable is volatile. It will be explained in detail later.

full of volatile Visibility Guarantee

In fact, the visibility of Java volatile is guaranteed to go beyond the volatile variable itself. The visibility guarantee is as follows:

    • If thread A writes a volatile variable, then thread B reads the same volatile variable, Then all the variables that are visible to thread A (the translator: not necessarily the volatile variable) will be visible to thread B after threads B reads the volatile variable before all threads a writes the volatile variable.
    • If thread A reads a volatile variable, then all variables that are visible to thread a when thread a reads this volatile variable (translator: Not necessarily a volatile variable) will also be read from the main memory.

Let's take a look at a code example:

The update () method writes three variables, of which only days is volatile.

Full volatile visibility guarantees that when a value is written to days, all variables that are visible to the thread will also be written to the main memory. That is, when a value is written to days, the values of years and months are also written to the main memory.

When reading the values of years,months and days, you can write:

Note the Totaldays () method first reads the value of days to the total variable. When the value of days is read, months and years are also read from the main memory. Therefore, using the above reading order, you can ensure that the most recent values are read to Days,months and years.

The challenge of order reordering

For performance reasons, the JVM and CPU are able to reorder the instructions as long as the semantics of the directives are kept consistent. For example, the following code:

These instructions can be reordered in the following order, but do not lose the original semantics of the program:

But when one of the variables is a volatile variable, the command Reflow poses a challenge. Let's take a look at the MyClass class in the previous example.

When the update () method writes values to days, the new write values of years and months are also written to the master memory. But what if the JVM would rearrange the order of these instructions as follows:

When the days variable changes, the values of months and years still write to master memory, but the new values are not written to months and years. The new value is therefore not properly visible to other threads. The semantics of the reordering instructions have changed.

Java has a solution for this problem. We'll see it in the next section.

Java volatile "occurred before (Happens-before ) "Guarantee

In order to address the challenge of order reordering, the Java volatile keyword provides a "before" (Happens-before) guarantee in addition to the visibility guarantee. Prior to occurrence guarantee:

    • Read/write operations on these other variables cannot be reordered after the write to the volatile variable if the read/write operation on some other variables originally occurred before writing to a volatile variable. Read/write operations before writing to a volatile variable are guaranteed to occur before the volatile variable is written. Note that the following situation can still occur: read/write operations on other variables that occurred after writing to a volatile variable may be reordered before writing to the volatile variable. Just the reverse is impossible. It is permissible from then to before, but not allowed from before to after.
    • If read/write operations on some other variables were originally taken after reading a volatile variable, then read/write operations on those other variables could not be reordered until the volatile variable was read. Note that the following situation can still occur: read operations on other variables that occurred before the read of a volatile variable may be reordered after reading the volatile variable. Just the reverse is impossible. From before to after is allowed, from after to not allowed.

The above "occur before" guarantee ensures that the volatile keyword is guaranteed for visibility.

volatile not always enough.

Although the volatile keyword guarantees that all read volatile variables are read from the main memory, and that all write volatile variables are written directly to the primary memory, there is still a case where declaring the variable as volatile remains insufficient.

In the above scenario, only thread 1 writes to the shared counter variable, and declaring counter as volatile can be sufficient to guarantee that thread 2 always sees the most recent write value.

In fact, if the newly written variable value does not depend on the first value of the variable (in other words, a thread does not need to read the value of a variable to compute a new value), even multiple threads can write a shared volatile variable, but the value of the variable in main memory is correct.

When a thread needs to read the value of a volatile variable first, and then generate a new value for the shared volatile variable based on that value, simply declaring the variable as volatile no longer guarantees the correct visibility of the variable.

This short period of time from reading a volatile variable to writing a new value to this variable creates a race condition. Competition status here means that multiple threads may read the same value as the volatile variable, generating a new value for the variable, and when the value is written back to main memory, multiple threads overwrite each other's values.

Multiple threads increasing the value of the same counter at the same time is the case where a volatile variable is not sufficient to ensure correctness. This situation will be explained in detail later.

Suppose thread 1 reads the shared counter variable value 0 to the CPU cache, increasing this value to 1 but has not yet written the changed value back to main memory. Thread 2 May read the value of this counter variable to 0, and put it into its own CPU cache. Thread 2 Next may also increase the value of counter to 1, and also does not write the updated value back to main memory. This situation:

Thread 1 and thread 2 are virtually out of sync. The value of this shared counter variable should be 2, but the value of each thread in their CPU cache is 1, and the value in main memory is still 0. This is a mess. Even if two threads write a value from the CPU cache to main memory, the value is still wrong.

when does volatile is enough to

As I said earlier, if two threads read and write a shared variable at the same time, it is not enough to simply declare the variable to be volatile. In this case you need to use the Synchronized keyword to guarantee the atomicity of the variable from read to write. Reading or writing a volatile variable does not block the read and write of other threads. If you want to block, you must use the Synchronized keyword around the critical section.

As an alternative to the Synchronized keyword, you can also use the atomic data types in the Java.util.concurrent package, such as Atomiclong or atomicreference.

If only one thread reads and writes a volatile variable, and the other thread reads only the value of the variable, the thread that reads the value is guaranteed to read the value of the most recent write to the volatile variable. If the variable is not declared as volatile, this will not be guaranteed.

The volatile keyword supports 32-bit and 64-bit variables.

volatile and Performance

Reading and writing to volatile variables can cause read and write to occur in main memory. The overhead of reading and writing to the main memory is far greater than the CPU cache. Access to volatile variables can also cause instructions to not be reordered, and reordering is a general technique for improving performance. So you should only use volatile variables when you really need to guarantee the visibility of variables.

Translator Summary:

    1. Volatile is used to ensure the visibility of multiple threads in a multi-CPU environment for changes in shared variable values
    2. Visibility issues are caused by the CPU cache
    3. If multiple variables need to address the visibility issue, not all variables need to be declared volatile. Visibility can also be guaranteed in the following situations:

Declare only one variable to be volatile, and then read the first to read the volatile variable, and write the last to write the volatile variable.

English website:

Http://tutorials.jenkov.com/java-concurrency/volatile.html

Java volatile keyword Full explanation-attached example

Related Article

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.