The role of the Java keyword volatile and how to use it

Source: Internet
Author: User
Tags visibility volatile

Let's take a look at what this keyword means:
volatile [? V?l?ta?l]
Adj. variable, unstable;
In translation, volatile means that the keyword is highly susceptible to change.
Volatile is the most lightweight concurrency synchronization mechanism in the Java language. This keyword has the following two functions:
1. Any modification to volatile variables, other threads in Java can perceive
2, volatile will prohibit command punch sorting optimization
Before explaining the volatile keyword in detail, there is a need to understand the Java memory model, otherwise it is difficult to gain a deeper understanding of the role of volatile. Java memory can be divided into heaps, stacks, method areas, and so on, as previously said. But from the point of view of combining physical devices, the layout of the memory model is designed as follows:

The memory model is designed so that the IO operation of physical memory is very time-consuming relative to the CPU's processing speed. This causes the CPU thread to end up with a quick calculation, which requires a lot of time to wait for the memory IO operation. To reduce this wait, the Java memory model introduces the concept of working memory. Working memory mainly uses the CPU or memory registers, the cache and so on the data buffering, reduces the CPU thread waits during the memory io.
In the Java memory model, any data-related operation of a thread is associated with and is only related to working memory. When the line Cheng (anti-theft connection: This article starts from http://www.cnblogs.com/jilodream/) to manipulate the data, the virtual opportunity first reads the data from the main memory and then places a copy of the data into the working memory. The Java thread then reads the copied data from the working memory and operates a completely new data, and then puts the data back into the working memory, overwriting the original value.
This can take advantage of the physical hardware:
(1) main memory, storage area large, but not speed, suitable for storage, not suitable for fast read and write
(2) The working memory, storage space is small, but fast, suitable for fast reading and writing, not suitable for storage
The Java thread is also prevented from reading and writing the data synchronization problem in main memory. Because the main memory is visible to each Java thread. If the Java thread is concurrently operating, it causes the data in main memory to be protected synchronously, otherwise the semantics of the error will occur.
However, there is still a problem with this: the data in working memory is copy data. In the course of a Java thread operation, the data in main memory may have changed, and the Java thread is equivalent to calculating and writing back with obsolete values. The problem is that what the data calls "synchronization" is the problem with the visibility of the lock to be handled (I'll talk about it later in the article).
How to solve this problem?
can only be handled in the form of a "lock". One of the functions of the volatile keyword is to form such a "lock":
If a variable is defined as volatile, each time the Java thread writes to the variable, it will add a "lock Addl $Ox 0" Operation instruction. This creates a "memory barrier" that, when the CPU writes this instruction to the main memory, tells the other working memory with which the instruction is stored plus an identity. Indicates that the variable has changed and that the copy data stored in the current working memory is obsolete (this process is called the kernel cacheinvalidate). When other threads need to use the variable to operate, the system will determine that the data in the current working memory is obsolete. This proactively refreshes the values in the main memory into the working memory underneath. Because the system has refreshed the value of the variable ahead of time in the process, the thread cannot see the data that is obsolete. Therefore, from the performance point of view, it can be considered that there is no data inconsistency.
there is a need to specifically emphasize the next long, double type. For instructions defined in the memory model, the data for the operation is 32 bits. If the data is 64 bits, then two instruction operations are required. For a 64-bit data type in a virtual machine: Double, long, because the time difference of two operations is required, causing the other thread to get a modified intermediate value.
However, the volatile memory barrier is specifically handled here to ensure that this intermediate value does not appear in the working memory of other CPUs. At the same time, commercial virtual machines have been specifically addressed to this issue: the reading and writing of 64-bit data is also atomic operation. is to prevent a long double of these two common types, because there is no increase in the volatile keyword, resulting in a strange value in working memory.
Another function of volatile is to prohibit the optimization of order reordering  
During the execution of instructions, the order of the instructions is often ordered by the order of optimization reordering, in order to ensure the speed of the CPU threads. In order to ensure that reorder instructions do not have any ambiguity and only increase in speed, the system will ensure that the results of the command optimization are consistent. That is, the results you obtain are the same as the results obtained without optimization, and there is no difference. However, because the order of instruction has changed, the system cannot guarantee that the data obtained by other threads will represent the current state correctly. The most classic here is the case initialization problem in singleton mode. See article: The 3rd method of a singleton pattern for design patterns.
because of the command rearrangement, the system will give the address to the instance variable (anti-theft connection: This article starts from http://www.cnblogs.com/jilodream/) before the end of the variable initialization. At this point the variables that other threads get are problematic: instance!=null, but the values inside are not initialized. This requires the use of the volatile keyword to suppress command reordering: The variable instance reference is given only after the instance has been initialized.
Another common example is:
when thread B refreshes the processing result of thread A, it is possible that thread A has not initialized the variable yet, but has refreshed the variable in advance, causing the state of the variable that thread B gets to be wrong.
therefore, when defining multi-threaded visible variables, it is important to add the volatile keyword to ensure that the variable is not optimized for the order of instruction, and that the value that is obtained by other threads is meaningless.
The order of the Java language in the "deep understanding of Java Virtual Machine," there is a sentence, summed up very good: if you observe in this thread, all operations are orderly. If you observe this thread on one other thread, all operations are unordered.
The front is that regardless of how the virtual machine optimizes the instructions, the current thread should be consistent in the semantics and results of the execution. ("line range behaves as a serial semantics" within-thread-as-if-serial-semantics). The back point is that the instruction will be re-ordered, and the value obtained in the other thread does not represent anything.
In fact, these two effects of volatile are interrelated: It is because volatile needs to ensure the visibility of variables, so the system can not be unordered intermediate instruction results into the main memory, so that other threads to use the visible, so the need to prohibit the order reordering. The result is guaranteed to reflect the current state of execution. (Here comes the concept of a happens-before principle, which I'll cover in the post)
the problem of volatile existence
said the two role of volatile, volatile also has its own shortcomings. That is, volatile does not guarantee atomicity:
As previously mentioned, when the volatile variable value is modified, it is flushed directly into main memory, and other threads can perceive it. But other threads continue to use this variable for calculation, but there is no guarantee that it will always be the most recent value. Give me a classic example .

1 volatile int a=0;2int  Add ()3{4     a++; 5 }

Two threads T1,t2 successively executes the Add) method, variable A has been self-increment. But the end result of a variable may be 1 or 2. This depends on whether the value of the T2 read variable A is before the first thread flushes a to main memory or after the main memory.
the a++ operation will execute three instructions at the end of execution:
1. Read a value from main memory
2, A=a+1
3. Write the value of a to main memory
when T1 executes the second step, if at this time T2 also read the value of a, then: the main memory a=0;t1 working memory is a=1;t2 working memory a=0, then T1 to perform a write-back a operation, but T2 because the value of a has been read in the working memory, so T2 after performing a a++ operation, The a=1 will still be written back to main memory, although the memory barrier is generated when the T1 is written back, but the T2 has been read and will not be actively refreshed during the self-increment phase. (Anti-Theft connection: This article starts from http://www.cnblogs.com/jilodream/) Otherwise, if you need to execute successive instructions, each time you have to actively refresh the variable, once the change has started, it is obviously impossible. This situation requires the programmer to pass the code itself to ensure that there is no problem.
Here we can see that the a variable is not because of the volatile keyword, but makes its own instructions in the outside world appears to be atomic.
Therefore, the use of volatile is limited by the following scenarios:
1, volatile can be written, but the value written should not depend on the old value
2. When confirming the invariance of a state, the volatile variable cannot be used as a factor.
These two points refer to similar semantics in the Java Concurrency Programming combat and in-depth understanding of Java virtual machines. The 1th is easier to understand. The 2nd is more abstract, here to explain: that is, volatile is suitable for judging whether it has changed, and is not suitable for judging whether it has not changed, because the volatile variable changes, there must be a change, the volatile does not change, it cannot be explained that there must not have changed.
as in the preceding article, a if still equals 0. cannot be considered at this time: 1, the Add method has not been called over 2, the whole has not been changed.

The role of the Java keyword volatile and how to use it

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.