--volatile keywords for communication and collaboration between threads

Source: Internet
Author: User
Tags volatile

In the last two articles I have introduced some basic communication between the threads, then this article will talk about the volatile keyword related knowledge. This keyword is seldom used in our daily development, and the class under the lock and concurrent packages of the JDK uses this keyword extensively because it has the following two features:

1. Ensure memory Visibility 2. Prohibit command reordering

The next step is to analyze this two-point feature, and I'll try to explain the relevant knowledge in the language that is most understandable.

What is visibility

This is certainly the case in a multithreaded environment where multiple threads need to access the same data in the primary memory address. If there is no volatile keyword, then thread a modifies that data, and thread B immediately reads that data, and the data in thread A and thread B is already different (the data that thread B reads or is not previously modified by thread a). Results that result from subsequent operations may differ from the imagined results. This is certainly something that needs to be avoided, and the volatile keyword can solve the problem here: if the data being accessed uses the volatile keyword modifier, then when a thread modifies that data, it must first write the newly modified value back to main memory. This ensures that the next thread that reads the variable is getting the most recent value of that data in main memory.

From the CPU level, we look at how to support volatile to ensure memory visibility:

Now everyone's computer processor is generally i3, i5, i7 processor, and these processors have a plurality of core (which is what we normally call dual-core, quad-core, six-core, etc.), each core has its own cache, you can refer to the following image:

The steps for the CPU to execute a single instruction are as follows:

1. Program-related data is loaded into main memory

2. Instruction-related data is loaded into the cache

3. Execute the instructions and store the results in the cache

4. Write the data in the cache back to main memory

There is no problem with this step of execution in a single thread, but unexpected results can occur in the case of multithreaded concurrency operations. Consider the following scenario:

1. A thread in core 0 reads a byte that is stored in the core 0 cache for the next direct use

2. At this point, a thread of core 3 also reads this byte, then the byte is also cached in the core 3 cache, when core 0 is the same data as the Core 3 cache

3. Then the core 0 thread modifies the byte and stores the modified result in the core 0 cache, at which point the thread of core 3 gets the execution right.

4. The core 3 thread starts executing the instruction, discovers that the byte data exists in its own cache, and then takes this byte directly to calculate. However, at this point in the core 3 cache this byte is still the core 0 thread modification before the data!!!

At this point, the problem arises, the core 3 thread does not take the latest data of the byte, but the old data to calculate, then the calculated results will be biased.

OK, the problem has been thrown, then how does the CPU solve this problem? is actually solved by a lock command. What is a lock directive? This concept is relatively low-level, interested in children's shoes can go to search the IA-32 manual, this manual has detailed explanation of what is the lock command and what the lock directive specifically did.

Here I will briefly summarize several functions of the lock command:

1. Lock bus/Lock cache line.

The 2.lock directive forces a thread to make modifications to a data in the cache, and the modified result must be synchronously written back to main memory, and the other thread must first read the latest data from main memory before executing the instruction.

3. Similar to the effect of memory barrier.

Among the several functions of the above lock directive, it is assumed that the 1th and 3rd children's shoes are not very clear about the concept. The 3rd relates to the knowledge of the Java memory model, which I will explain in detail in the JVM Virtual machine topic, which is explained first in the 1th.

Bus definition: The CPU cache and the media for memory exchange data. As long as the CPU cache wants to exchange data with memory, it must go through the bus.

The earlier lock directive did this: when a CPU cache wants to write data to memory, the lock command locks the entire bus, that is, the entire bus can only cache the service for that CPU. So what if other CPU caches want to write their own data into memory? I'm sorry, but wait until the current CPU cache and memory swap out the bus execution, the next CPU cache can continue to get the bus execution, so as to be able to read the latest data from the main memory, after the execution of instructions to write the latest results in memory. It is very inefficient to see the early lock instructions, which can only have one CPU cache and memory for data exchange at the same time. So how to solve the problem of low efficiency? Modern processors use one of the most mainstream protocols-cache conformance protocols.

Definition of Cache Consistency protocol: When a core in the CPU wants to write back the results of a command after it has been executed, it must first request permission from the bus. Once the permission is obtained, the thread can exchange data with the main memory, and at this point the other CPU cores are constantly "sniffing" the bus, and once the memory address of the updated data is changed, the other CPU will immediately set the data cached in the memory address in its cache to be invalid. When the next execution instruction needs to use the cached data of this memory address, the cache is invalid and the current data must be loaded into main memory before the specific instructions are executed. This method only locks the cache rows of memory addresses that have changed in main memory at the same time, does not lock the entire bus, and other cache rows can be exchanged for data.

Here is a cache line corresponding to a number of states, you can compare with the above cache consistency Protocol of the various scenarios:

Now we look back at the problem raised in Figure 6-40, because there is a cache consistency protocol exists, the core 0 of the thread to get bus execution to write the latest results back to the main memory, Core 3 will sniff this part of the memory address data has changed, then Core 3 will own this part of the cache is invalidated.

When the next core 3 thread needs to execute the instruction, it will get the latest data from main memory before executing. Cache consistency is the way to ensure the visibility of data between threads.

What is reordering

Simply put, reordering is the compiler and the processor that automatically re-sorts the instructions in the program to improve execution efficiency. So the order in which the JVM actually executes the instructions is not consistent with what we define in the program. Reordering does not have any problems with single-threaded threads, because no matter how it is reordered, just make sure the final execution is correct. However, in a multithreaded environment, it is possible that the result of a thread being re-ordered is not the latest result, which makes the subsequent calculations inconsistent with the expected results. Volatile in order to solve this problem, it provides a function of "Prohibit command reordering".

So how does volatile do it? We know that the problem occurs in a multithreaded environment because the read operation of one thread occurs before the write operation of another thread, and this occurs because of the order reordering. So as long as the reading and writing operations will not be ordered re-ordering, not OK?

So volatile makes a hard rule that all read and write operations involving volatile variable modifier variables do not allow reordering with other instructions. Both the volatile read instruction and the volatile write instruction insert a layer of "barrier" before and after the directive to prevent them from being reordered by the JVM. This ensures that the volatile modified variables are changed, and all subsequent threads will be reading the latest data, the so-called "no reordering".

When do I use volatile variables?

The two properties of volatile are described above, so when do you use volatile variables? I personally recommend it. Volatile variables are required only if the program needs to determine the execution logic through a variable of a Boolean type, which should be decorated with a volatile variable in a multithreaded environment. As shown in the following code:

1     volatile Boolean Flag; 2     ..... 3      while (! flag) {4        dosomething ();           5     }

Note: Why is it recommended to use volatile variables only in this case? Because this is related to a characteristic of volatile, we must keep in mind that volatile can only guarantee visibility , but it cannot guarantee atomicity !!! As above, reading and writing to Boolean variables is inherently atomic, so using volatile variables to ensure visibility ensures that the flag variable is always up-to-date. However, as with a++, the use of volatile modifier variable A does not guarantee that the results will be correct in a multithreaded environment! Because a++ is not an atomic operation, it actually contains a 3-step instruction: 1. Gets the value of the current a variable, 2. Increment the value from 1;3. Writes the result of the increment back to the A variable. In this case, volatile can only guarantee that the first step "get the value of the current a variable" is the most recent, but there is no guarantee that a thread will not be interrupted by another thread when executing the 3-step instruction. Consider the following scenario:

1. Assuming that a variable is 1, at the beginning a thread executes steps 1th and 2nd, at which time the CPU is assigned to a, and the value of a cache is 2, and then the B thread acquires execution rights.

The 2.B thread also performed steps 1th and 2nd, but before the 3rd step was taken back by a execution, a 2 of the cache was written to the A variable, and a at this time the value is 2.

3.A execution, B also grabbed the execution, the problem arises: B The value of the cache is also 2, but it did not re-read the value of a, but instead of a direct implementation of the 3rd step, 2 of its own cache is written to the A variable, then a final value is 2.

As you can see, even though two threads perform a++ operations, the final result is not 3 but 2 (equivalent to one thread execution is invalid), which can be a big problem in business! Because the code in our everyday application is a combination of code, that a business must be done by a set of code, rarely does a situation where a business can be done simply by atomic manipulation. So what about this situation? Here we need another tool to deal with, but also the next article explains the knowledge point--synchronized keyword.

Ok,volatile of the relevant knowledge to here is all introduced, I hope you learn from this article. This article a lot of content refer to the Blog Park (May Cangjie) Great God's "is to you understand the volatile keyword analysis" This article, look at the knowledge written by the great God, and then thinking, I think it is a good way to learn. The next article will explain the usage and features of our most commonly used lock--synchronized keywords.

--volatile keywords for communication and collaboration between threads

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.