Java multithreading orderliness-power node

Ordering refers to the circumstances under which memory access operations performed by a thread running on one processor appear out of order from other threads running on another processor.

Out of order means that the order of memory access operations appears to have changed.

Reorder

In the environment of multi-core processors, the sequence structure written, the order of execution of this operation may not be guaranteed:

The compiler may change the order of the two operations;

The processor may not execute in the order of the target code;

This kind of multiple operations performed on one processor may be different from the order specified by the target code in the view of other processors. This phenomenon is called reordering.

Reordering is an optimization for the orderly operation of memory access, which can improve the performance of a single-threaded program without affecting the correctness of a single-threaded program. However, it may affect the correctness of a multi-threaded program, that is, it may cause thread safety issues.

Reordering is similar to the visibility problem, which is not inevitable.

Several concepts related to the order of memory operations:

The source code sequence is the memory access sequence specified in the source code.

Program sequence, the memory access sequence specified by the object code running on the processor.

Execution order, the actual execution order of memory access operations on the processor.

Perception order, the order of memory access operations of this processor and other processors as perceived by a given processor.

Reordering can be divided into two types: instruction reordering and storage subsystem reordering:

Instruction reordering is mainly caused by the JIT compiler and processor, which means that the program sequence is not the same as the execution sequence.

The reordering of the storage subsystem is caused by the cache and the write buffer, and the perception order is inconsistent with the execution order.

Instruction reordering

When the source code sequence is inconsistent with the program sequence, or the program sequence is inconsistent with the execution sequence, we say that instruction reorder has occurred.

Instruction rearrangement is an action that does adjust the order of instructions and reorder the target instructions.

The javac compiler generally does not perform instruction reordering, while the JIT compiler may perform instruction reordering.

The processor may also execute instruction reordering, making the execution order inconsistent with the program order.

Instruction rearrangement will not affect the correctness of the results of single-threaded programs, and may cause unexpected results in multi-threaded programs.

Storage subsystem reordering

The storage subsystem refers to the write buffer and the cache.

Cache is a cache designed to match the processing speed of the main memory in the CPU.

Write buffer (Store buffer, Write buffer) is used to improve the efficiency of write cache operations.

Even if the processor executes two memory access operations strictly in program order, under the action of the storage subsystem, the perception order of these two operations by other processors is inconsistent with the program order, that is, the order of the two operations looks like There has been a change, this phenomenon is called storage subsystem reordering.

The storage subsystem reordering does not really adjust the order of instruction execution, but causes a phenomenon that the order of instruction execution is adjusted.

The storage subsystem reorders objects as a result of memory operations.

From the perspective of the processor, reading memory is to load data from the specified RAM address to the register, which is called the Load operation; writing memory is to store the data in the RAM storage unit represented by the specified address, which is called the Store operation. There are four possibilities for sorting:

● LoadLoad reordering, one processor performs two read operations L1 and L2 successively, and the perception order of the two memory operations by other processors may be L2->L1.

● StoreStore reordering, one processor executes two write operations W1 and W2 successively, and the perception order of the two memory operations by other processors may be W2->W1.

● LoadStore reordering, one processor executes the memory read operation L1 first and then executes the memory write operation W1. The perception order of other processors for the two memory operations may be W1->L1.

● StoreLoad reordering, one processor executes the memory write operation W1 first and then executes the memory read operation L1. Other processors may perceive the two memory operations in the order L1->W1.

Memory reordering is related to the specific processor microarchitecture, and the memory reordering allowed by processors of different architectures is different.

Memory reordering may cause thread safety issues. Suppose there are two shared variables int data = 0; boolean ready = false;

Processor 1

Processor 2

data = 1; //S1

ready = true; //S2

while( !ready){} //L3

sout( data ); //L4

Seemingly serial semantics

The JIT compiler, processor, and storage subsystem reorder the results of instructions and memory operations according to certain rules, creating an illusion for single-threaded programs-instructions are executed in the order of the source code. It is called seemingly serial semantics. It does not guarantee the correctness of a multithreaded environment program.

In order to ensure the seemingly serial semantics, statements with data dependencies will not be reordered, and only statements without data dependencies will be reordered. If two operations (instructions) access the same variable, and one of the operations ( Instruction) is a write operation, then there is a data dependency between these two operations.

Such as:

x = 1; y = x + 1; The operand of the next statement contains the execution result of the previous statement;
y = x; x = 1; First read the x variable, and then update the value of the x variable;
x = 1; x = 2; Two statements simultaneously write to a variable

If there is no data dependency, it may be reordered, such as:

double price = 45.8;
int quantity = 10;
double sum = price * quantity;

Statements that have control dependencies are allowed to be rearranged. The execution result of one statement (instruction) will determine whether another statement (instruction) can be executed. These two statements (instructions) have a control dependency (Control Dependency). For example, in if Reordering is allowed in the statement. There may be a processor that executes the if code block first, and then judges whether the if condition is established.

Ensure the order of memory access

You can use the volatile keyword and the synchronized keyword to achieve order.

Guess you like

Origin blog.csdn.net/weixin_49543720/article/details/110482860