One of the Java models: JMM (Java memory model)

Source: Internet
Author: User
Tags visibility volatile

I. INTRODUCTION

    When the computer executes the program, each instruction is executed in the CPU, and the process of executing the instruction must involve the reading and writing of the data in memory, the data in the previous computer is stored in main memory, because the CPU executes very fast, This results in a very slow rate of reading and writing compared to the data, which can result in a significant reduction in CPU execution efficiency, and the CPU cache is slowly occurring due to these factors. When the program is running, the data required for the operation will be copied from the main memory to the cache, and then directly through the high-speed CPU cache to write and read the data so that can greatly improve the speed of the program, everything has a good and bad, in the speed of ascension also caused the problem of concurrency.

1 i= i +1;

This code is believed to have been written by a yard farmer, the self-increasing operation. There is no problem with this code in a single thread, and each increment can fetch the added number. However, in multi-threaded, such as three threads execute this code, at this time the main memory value is 1, each thread internal CPU cache value is also 1, then thread 1 for self-increment operation, the value will become 2, and then write back to the cache, but at this time thread 2 is executed, the value in the cache in thread 2 is 1, At this point, the thread 2 took its own 1 to do a self-increment operation or to obtain 2, write back to their own cache, resulting in an increase of two times, but the resulting value may only increase once. This is the problem with cache inconsistencies. The relationship between the main memory and the CPU cache above is the JMM model.

Second, JMM (Java memory model)

    In fact, there is no real Java memory model, JMM is also an abstraction of the model, so that developers can better understand the Java concurrency between the communication process between threads. So what is the jmm of Daniel's abstract appearance?

    In Java, all instances, static fields, and arrays are stored in heap memory, and heap memory is shared between threads. Local variables, and so on, are not shared in threads, which is owned independently by each thread, and these variables do not have concurrency problems and are not affected by JMM. Communication between Java threads is controlled by JMM, and JMM determines when a thread's write to a shared variable is visible to another thread. It's also classic, the shared variables between threads exist in the main memory, and when the thread needs to be used it will automatically replicate to the thread-local cache, and all read and write subsequent operations will be the data in this cache. Here's a look at the JMM abstract model diagram presented on the Web:

The relationship between threads is clearly demonstrated: if thread A wants to communicate with thread B, first the shared variable copy in thread A changes to be flushed back to main memory from local memory. Second, thread B wants to read to the changed value in thread A and must go back to the main memory to read a copy of the data to overwrite its own local data. The subsequent operation is a changed variable in thread A. The following shows the entire execution process:

From the first example, you can conclude that there are two possible scenarios:

  The first type: Thread A has a self-increment operation, the value is written to local memory A, before it can be flushed back to the main memory at this time B has been operating, B got the value of its own local memory B caused by two times but the result is only added once, it will lead to thread insecurity.

  Second: Thread A has a self-increment operation, the value is written to local memory A, and the new value is flushed back to main memory, at which point B gets the main memory of the data discovery has been increased once to call the a thread to return the latest results of a call again, the results of the operation is normal.

In fact, the overall process is very simple is a changed the value of the notification b,b know you have changed to use the latest value for the next operation. Only this process must pass through the main memory.

The above is a description of an abstract model of JMM and a process for concrete communication at the bottom of the thread. It is also said that to ensure concurrency security, you must ensure that every change in a shared variable must be seen by other threads. What are the requirements for satisfying security? Here are some requirements to meet the Concurrency security features:

  First: atomicity Assurance

    What is atomic, the vulgar point is that the entire operation can be completed in one step and cannot continue to split into multiple steps to proceed. The precise one is a process that is either performed by everyone, and who quits in the middle, and everyone quits.

A very popular example is the life of the bank transfer, I transferred to a friend 100 yuan This operation involves a lot, first of all my account will be reduced by 100, the light of my account reduced by 100 useless Ah, friend's account more than 100 yuan, Otherwise it would be 100 of the bank to eat the white, right? This process is an atomic operation, either my account is deducted money, the friend account is more money, or I have to account not to deduct money, friend's account is not much money. These two operations make up a set of atomic operations that guarantee security.

Second: Visibility Assurance

What is visibility, the above jmm explanation is clear at a glance, is nothing more than a shared variable changes in a thread, this change for all other threads must be visible.

Visibility is also well understood, such as the following section of code

1 int i =0; 2 i = ten; 3 //above thread 1 executes, the following thread 2 executes 4 j = i;

First, I was assigned a value of 0, followed by a value of 10, and then assign the value of I to J, the process assumes that thread 1 starts to perform the initialization assignment and 10 is assigned to I, in this process the thread 1 has not had time to refresh the value back to main memory, at which point 2 begins execution, Then thread 2 reads probably just its initial value of 0, which is the result of a thread that is unsafe.

Third: the guarantee of order

Order is the most difficult one to understand in three guarantees, because this involves reordering the processor and compiler layers. First of all, what is validity, single-threaded, code execution is sequential, but with reordering, the compiler will perform a reordering of the code in the event that the result is not changed. Here we go. This is also a point that affects the concurrency security of the program, and then the reordering.

In concurrency, the above three features are guaranteed, and your program is a concurrency-safe program. and developers to develop concurrent projects is constantly in the maintenance of the above three features to ensure that their own program concurrency security.

Three. Re-order

    The above mentioned reordering, which is an optimization method made by the compiler and the processor at the instruction level, with a total of three classes of reordering:

      First: The reordering of compiler optimizations. The compiler can re-determine the order in which the programs are executed without changing the single-line semantics.

      Second type: command-level parallel reordering. Modern processors use instruction-level parallelism to overlap multiple CPU instructions, and the processor can change the order in which the programs are executed if there is no data dependency and some innate sequential operations are performed.

      The third type: The reordering of the memory system. Because the processor uses the cached read and write buffers, this makes the load and storage operations appear to be executing in a disorderly sequence.

That is, when we are finished, the program goes through the three-phase reordering process from the source code execution through to the final execution:

These reordering may cause memory visibility issues in multithreaded programs. Of course, it is not arbitrary reordering, the processor and the compiler will not be able to break the original execution of the program has the semantics of the implementation of the situation before reordering, such reordering in a single-threaded process will not cause problems in the program, but in the multi-threaded situation will have a great impact. Modern processors use write buffers to temporarily hold data written to memory. The write buffer guarantees the continuous operation of the instruction pipeline and avoids the delay that occurs when the processor pauses to wait for the data to be written to the memory. For a buffer, it improves the efficiency of the processor, but it also poses some problems: the order in which the processor performs the read/write operation on memory does not necessarily coincide with the order in which the memory actually occurs in the read/write operation. For example, the following code:

1 // processor a performs 2 a = 1; // A1 3 x = b; // A2 4 // Processor B performs 5 b = 2; // B1 6 y = A; // B2

Assuming that both processor A and processor B are executed sequentially then the final result should be x=1,y=2, but the result may be x=y=0, for the following reasons:

Follow the process should be to write back to the local memory, and then write back to the main memory, and then go to the main memory to read the relevant variables, the result is x=1,y=2 but because the existence of reordering may not have time to write back to the main memory has already started to read the data is x=y=0 this result. Because the write buffer is visible only to its own processor, it may cause the processor to perform memory operations in a different order than the actual operation. So what guarantees concurrency security in multiple processors? In Java, memory barrier directives are provided to prohibit the reordering of some processor layers, with four memory barriers:

Of course, in addition to the memory barrier there are some innate order of execution, these orders can not be re-ordered to destroy, that is, the famous Happens-before principle:

In JMM, if the result of one operation needs to be visible to another, there must be a happens-before principle between the two operations, and it is also possible to simplify concurrent development with these principles in mind. Below is a detailed list of happens-before rules

Program Order rules: In a single thread, in the order of the Code execution, the preceding operation is performed first in the following operation.

Manage locking rules: a unlock () operation Happens-before any thread to obtain the operation of this lock.

Volatile variable rule: a write operation on a volatile variable happens-before the read operation of any thread after the variable.

Thread Start rule: the Start () method of the Thread object Happens-before any other operations after the thread.

Transitive rule: If operation a happens-before operation B, Operation b happens-before Operation C, then operation a must happens-before operation C.

Here's what you need to note: The specific happens-before principle between the two operations does not mean that the previous operation must precede the latter operation, and he guarantees that any results from the previous operation are visible to subsequent operations. Here's a look at the diagram of Happens-before and JMM:

There is a qualification for reordering the compiler and the processor itself, which is the as-if-serial semantics, that is, the program that was said to be reordered when it is run, but its reordering is not arbitrarily reordered, he must satisfy the results and semantics that do not affect the program. This is also the core of as-if-serial semantics: No matter how your program is reordered, it doesn't affect the original results of my program. In order to comply with the as-if-serial semantic compilers and processors do not reorder the operations that exist since the data exists, because this reordering affects the results of program execution. For example, the following section of code:

1 int a = 1; 2 int b = 2; 3 int c = a+b;

A very simple operation is to define two variables, and the third variable is the value of the first and second variables, in single-threaded int a = 1, and int b = 2; The two operations may be re-ordered may first define a, but the final step is definitely the last. This is the role of as-if-serial semantics. Assuming that the above operation is divided into three steps, the process is:

There is no relationship between the a operation and the B operation between the two operations defined two variables, but the C operation depends on a also depends on B, through this dependency, the compiler finally decided that C can not be ranked before the A and before the B, if you allow reordering then this operation will change, But A and B have no relationship between the arbitrary reordering, and the reordering will not affect the results of the program. There are two possible sequences of final executions:

Four. Sequential consistency

    Sequential consistency facilitates concurrent programming and establishes the rules. It elaborates on two parts:

       First, all operations within each thread must be executed in the order of the program.

       Second, the interleaved order of thread execution can be arbitrary, but the overall execution order of the entire program seen by all threads is consistent.

When it comes to concurrency, many people mistakenly think that concurrency is the same as multiple threads running at the same time, in fact, the idea is not, the CPU can only execute one thread at a time, through a pointer-like thing in the thread to constantly switch, when a thread gets CPU resources, it is the turn of the threads to execute, Only one thread at a time can gain access to the CPU's resources. Say two threads a thread A and a thread b,a there are three operations, there are three operations in B, and the Order of operations for each thread is 1->2->3. If the concurrency of this brother is synchronized, this sequence of execution is formed:

If these two threads are not synchronized, then their execution is the following procedure:

unsynchronized programs in the sequential consistency model, although the overall order of execution is unordered, all threads see only a consistent overall order of execution. For example, threads A and B see the Order of execution: B1, A1, A2, B2, A3. This guarantee is achieved because each operation in the sequential consistent memory model must be immediately visible to any thread. However, there is no such guarantee in JMM. The unsynchronized program in JMM not only the overall order of execution is unordered, but also the order in which all threads see the execution of operations may be inconsistent. For example, when the current thread caches the written data in local memory, the write is only visible to the current thread until it has been flushed to the main memory, and viewed from the perspective of other threads, it is considered that the write operation has not been executed by the current thread at all. This write operation can be visible to other threads only after the thread has flushed the data written in local memory to the main memory. In this case, the execution order of the operations that the current thread and other threads see is inconsistent.

Five. Summary

    JMM is a language-level memory model, and understanding JMM helps in a deeper understanding of concurrent programming. JMM the impact of memory visibility on three Java programs:

      Single-threaded: A single-threaded procedure does not cause memory visibility issues, and the compiler, runtime, and processor are common to ensure that the execution of a single-threaded process is the same as that of the thread in the sequential consistency model.

      Programs that are correctly synchronized: the execution of the correctly synchronized multithreaded program will be consistent, using the lock or lock operation JMM to prohibit or limit the non-secure reordering of compilers and processors.

      unsynchronized Programs: JMM provides only basic security such as Happens-before and as-if-serial semantics within a single thread.

    Show the results of the three program executions :

==================================================================================

No matter how much bitterness and hardship experienced in the years, tell yourself that the wind and rain itself is a kind of connotation, efforts to face, but is a fate of drifting, since on the road, then the destination is necessarily the front.


==================================================================================

One of the Java models: JMM (Java memory model)

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.