Java Concurrency programming volatile keyword parsing

Source: Internet
Author: User
Tags volatile

Http://www.importnew.com/18126.html
Http://www.importnew.com/20566.html
Http://www.importnew.com/19745.html

Original address: Java concurrency programming: voldatile keyword parsing

Volatile this keyword may have been heard by many friends, and may have been used. Before Java 5, it was a controversial keyword, because using it in a program often led to unexpected results. After Java 5, the volatile keyword was able to regain its vitality.

Although the Voldatile keyword is simple to understand literally, it is not an easy task to use well. Since the volatile keyword is related to the memory model of Java, before we tell about the volatile key, let's take a look at the concepts and knowledge associated with the memory model, and then analyze how the volatile keyword is implemented. Finally, several scenarios with volatile keywords are given.

I. Related concepts of the memory model

As we all know, when the computer executes the program, each instruction is executed in the CPU, while executing the instruction process, it is bound to involve the reading and writing of the data. Since the temporary data in the program is stored in main memory (physical RAM), there is a problem, because the CPU is executing fast, and the process of reading data from memory and writing data to memory is much slower than the CPU executing instructions. Therefore, if the operation of the data at any time through the interaction with the memory, it will greatly reduce the speed of instruction execution. So there's a cache in the CPU.

That is, when the program is running, the data required for the operation is copied from the main memory to the CPU cache, then the CPU can be calculated directly from its cache to read data and write data to it, when the end of the operation, then the cache of data flushed to main memory. A simple example, such as the following code:

1

When the thread executes this statement, the value of I is read from main memory and then copied to the cache, then the CPU executes the instruction to add 1 to I, then writes the data to the cache, and finally flushes the most recent value of I in cache to main memory.

There is no problem with this code running in a single thread, but running in multi-threading can be problematic. In multi-core CPUs, each thread may run on a different CPU, so each thread runs with its own cache (this is actually the case for a single-core CPU, but it is performed separately in the form of thread scheduling). In this paper we take the multi-core CPU as an example.

For example, there are 2 threads executing this code, if the initial value of I is 0, then we want two threads to execute after the value of I becomes 2. But will that be the case?

There may be a situation where, initially, two threads read the value of I in the cache of their respective CPUs, then thread 1 adds 1, then writes the latest value of I to memory 1. At this point in the cache of thread 2 The value of I is still 0, after adding 1 operations, I is the value of 1, and then thread 2 writes the value of I to memory.

The value of the final result I is 1, not 2. This is a well-known cache consistency issue. It is commonly said that the variable accessed by multiple threads is a shared variable.

That is, if a variable exists in multiple CPUs (typically in multithreaded programming), there may be a problem with cache inconsistencies.

To address the problem of cache inconsistencies, there are generally 2 workarounds:

    • By adding a lock# lock on the bus
    • By caching the consistency protocol

These 2 approaches are available at the hardware level.

In the early CPU, the problem of cache inconsistency was solved by adding lock# lock on the bus. Because the CPU and other components communicate through the bus, if the bus plus lock# lock, that is, blocking other CPU access to other parts (such as memory), so that only one CPU can use this variable memory. For example, if a thread executes i = i +1 in the above example, if a lcok# lock is signaled on the bus during the execution of this code, then the other CPU can read the variable from the memory where the variable I resides and then perform the appropriate operation only after the code is fully executed. This solves the problem of cache inconsistency.

However, there is a problem with the above approach because the other CPUs are unable to access the memory during the locking of the bus, resulting in inefficiency.

So there is a cache consistency protocol. The best known is the Intel Mesi protocol, which guarantees that a copy of the shared variables used in each cache is consistent. The core idea is that when the CPU writes the data, if the variable that is found to be an action is a shared variable, that is, a copy of the variable exists in the other CPU, a signal is signaled to the other CPU that the cache row of the variable is invalid, so that when the other CPU needs to read the variable, The cache line that caches the variable in its own cache is not valid, and it is re-read from memory.

Two. Three concepts in concurrent programming
In concurrent programming, we typically encounter the following three problems: atomicity, visibility, order. Let's take a specific look at these three concepts:

    1. Atomic Nature
      That is, one operation or multiple operations are executed completely and the process of execution is not interrupted by any factor, or it is not executed.

A classic example is the bank account transfer problem:

For example, from account A to account B to 1000 yuan, then must include 2 operations: from account a minus 1000 yuan, to account B plus 1000 yuan. Imagine what the consequences would be if the 2 operations did not have atomic properties. If you subtract $1000 from account A, the operation suddenly stops. Then from B took out 500 yuan, remove 500 yuan, and then to account B plus 1000 yuan operation. This will result in account a although minus 1000 yuan, but account B did not receive this turn over the 1000 yuan.

So these 2 operations must be atomic to ensure that there are no unexpected problems.

Similarly, what happens in concurrent programming?

For the simplest example, let's think about what happens if the process of assigning a 32-bit variable is not atomic.

9 ;

If a thread executes to this statement, let's assume that a 32-bit variable assignment includes two procedures: a low 16-bit assignment and a high 16-bit value.

Java Concurrency programming volatile keyword parsing

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.