In-depth understanding of the Java memory Model (iii)-sequential consistency

Source: Internet
Author: User

This article belongs to author original, the original text is published in Infoq:http://www.infoq.com/cn/articles/java-memory-model-3

Data competition and sequential consistency guarantee

Data contention exists when the program is not synchronized correctly. The Java memory Model specification defines the competition for data as follows:

    • Write a variable in a thread,
    • Read the same variable on another thread,
    • and write and read are not sorted by synchronization.

When the code contains data competition, the execution of the program often produces counterintuitive results (as in the previous chapter). If a multithreaded program can be synchronized correctly, this program will be a non-data competition.

JMM the following guarantees for the memory consistency of correctly synchronized multithreaded threads:

    • If the program is synchronized correctly, the execution of the program will have sequential consistency (sequentially consistent) – that is, the execution result of the program is the same as that of the program in the sequential consistent memory model (as we will see now, this is a very strong guarantee for programmers). The synchronization here refers to the generalized synchronization, including the correct use of common synchronization primitives (Lock,volatile and final).
Sequential consistent memory model

Sequential consistent memory model is a theoretical reference model idealized by computer scientists, which provides a very strong guarantee of memory visibility for programmers. The sequential consistent memory model has two major features:

    • All operations in a thread must be executed in the order of the program.
    • (regardless of whether the program is synchronized) all threads can see only a single order of operation execution. In the sequential consistent memory model, each operation must be atomically executed and immediately visible to all threads.

The sequential consistent memory model provides the programmer with the following views:

Conceptually, the sequential consistency model has a single global memory that can be connected to any thread by a switch that swings around. At the same time, each thread must perform a memory read/write operation in the order of the program. As we can see, at most one thread can be connected to memory at any point in time. When multiple threads are executing concurrently, the switch device in the diagram can serialize all the memory read/write operations of all threads.

For a better understanding, let's go through two of the features of the sequential consistency model to further illustrate.

Assume that there are two threads A and b executing concurrently. Where a thread has three operations, their order in the program is: A1->A2->A3. The b thread also has three operations, and their order in the program is: B1->B2->B3.

Suppose these two threads use a monitor to properly synchronize: the three operation of a thread releases the monitor after execution, and then the B thread gets the same monitor. Then the execution effect of the program in the sequential consistency model will look like the following:

Now let's assume that the two threads are not synchronizing, and the following is the execution of this unsynchronized program in the sequential consistency model:

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->b3. 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 and is not flushed to the main memory, the write is only visible to the current thread, 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.

Sequential consistency effect of the synchronization program

Here we reorderexample the previous example program with a monitor to see how the correctly synchronized programs have sequential consistency.

Take a look at the following sample code:

classSynchronizedexample {intA = 0;BooleanFlag =false; Public synchronized voidwriter () {a= 1; Flag=true;} Public synchronized voidReader () {if(flag) {inti =A; ... }}

In the example code above, suppose a thread executes the writer () method, and the B thread executes the reader () method. This is a properly synchronized multithreaded program. According to the JMM specification, the execution result of the program will be the same as the execution result of the program in the sequential consistency model. Here is a comparison of the execution timing of the program in two memory models:

In the sequential consistency model, all operations are executed serially in the order of the program. In JMM, the code within the critical section can be reordered (but JMM does not allow the code in the critical section to "Escape" beyond the critical section, which destroys the semantics of the monitor). JMM will do some special processing at two key points when exiting the monitor and entering the monitor, allowing the thread to have the same memory view as the sequential consistency model at both points of time (as explained in detail). Although thread A is reordered within a critical section, thread B cannot "observe" the reordering of thread A in the critical section because of the nature of the monitor's mutex execution. This reordering not only improves the efficiency of execution, but also does not change the execution result of the program.

From here we can see the basic policy of JMM in concrete implementation: without changing (correctly synchronized) program execution results, as far as possible for the compiler and processor optimization open the door.

Execution characteristics of an unsynchronized program

For multithreaded programs that are not synchronized or are not synchronized correctly, JMM provides only minimal security: The value read when the thread executes, either the value written by a previous thread, or the default value (0,null,false), JMM guarantees that the value read by the thread read operation will not be fabricated out of nothing (out of the thin Air). For minimal security, the JVM allocates objects on the heap, first clearing 0 of the memory space before allocating the objects (the two operations are synchronized internally by the JVM). As a result, the default initialization of the domain is complete when allocating objects in zeroed memory space (pre-zeroed memories).

JMM does not guarantee that the execution result of the unsynchronized program is consistent with the execution result of the program in the sequential consistency model. Because the unsynchronized program executes in the sequential consistency model, it is unordered in its entirety and its execution results are unpredictable. It is meaningless to ensure that the results of the unsynchronized program execution in two models are consistent.

As with the sequential consistency model, the unsynchronized program executes in JMM and is unordered in its entirety, and its execution results are unpredictable. At the same time, there are several differences in the execution characteristics of the unsynchronized program in the two models:

    1. The sequential consistency model guarantees that operations within a single thread are executed in the order of the program, while JMM does not guarantee that operations within a single thread will be executed in the order of the program (such as the reordering of multithreaded programs correctly synchronized above in the critical section). This has already been said before, and here we will not repeat it.
    2. The sequential consistency model guarantees that all threads see only a consistent sequence of operations execution, while JMM does not guarantee that all threads will see a consistent sequence of operations execution. This point has already been mentioned before, here will not repeat.
    3. JMM does not guarantee that read/write operations on 64-bit long and double variables are atomic, and the sequential consistency model guarantees atomicity for all memory read/write operations.

The 3rd difference is closely related to the working mechanism of the processor bus. In a computer, data is passed between the processor and memory through the bus. Each time the data transfer between the processor and the memory is done through a series of steps called Bus transaction. The bus transaction consists of a read transaction (transaction) and a write transaction (write transaction). A read transaction transmits data from memory to the processor, the write transaction transmits data from the processor to memory, and each transaction reads/writes one or more physically contiguous words in memory. The key here is that the bus synchronizes transactions that attempt to use the bus concurrently. The bus prevents all other processors and I/O devices from performing memory read/write during the execution of a bus transaction on one processor. Let's use a schematic diagram to illustrate how the bus works:

As shown, assuming that the processor, a, B, and C simultaneously initiate bus transactions to the bus, the bus arbitration will adjudicate the competition, and here we assume that the bus determines processor a wins the competition after the arbitration (the bus quorum ensures that all processors have fair access to the memory). At this point, processor a resumes its bus transaction, while the other two processors wait for the bus transaction of processor A to complete before they begin to perform memory accesses again. Assuming processor a performs a bus transaction (whether the bus transaction is a read transaction or a write transaction), processor D initiates a bus transaction to the bus, at which point the request from processor D is blocked by the bus.

These mechanisms of the bus can execute all processor-to-memory accesses in a serialized manner, and at any point in time, only one processor can access the memory. This feature ensures that memory read/write operations in a single bus transaction are atomic.

On some 32-bit processors, there is a significant overhead if a write operation to 64-bit data is required to be atomic. In order to take care of this processor, the Java language Specification encourages, but does not impose, the JVM's write to the 64-bit long variable and the double type variable to be atomic. When the JVM is running on such a processor, a write operation of a 64-bit long/double variable is split into two 32-bit writes to execute. These two 32-bit writes may be assigned to different bus transactions, at which point the write to this 64-bit variable will not be atomic.

When a single memory operation is not atomic, it can have unintended consequences. Please see below:

As shown, suppose processor a writes a long variable, and processor B reads the long variable. A 64-bit write operation in processor A is split into two 32-bit writes, and the two 32-bit writes are assigned to different write transactions. At the same time, the 64-bit read operation in processor B is assigned to a single read transaction to execute. When processor A and b press the timing to execute, processor B will see an invalid value that is only half written by processor a.

Note that in the old memory model prior to JSR-133, a read/write operation of a 64-bit long/double variable can be executed by splitting it into two 32-bit read/write operations. Starting with the JSR-133 memory model (that is, starting with JDK5), only the write operation of a 64-bit long/double variable can be split into two 32-bit writes to execute, and any read operation in the JSR- All 133 must be atomic (that is, any read operation must be performed in a single read transaction).

In-depth understanding of the Java memory Model (iii)-sequential consistency

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.