Let’s talk about how Hotspot memory barrier prevents instruction reordering


Insert image description here

1 Introduction

A memory barrier, also known as a memory fence, memory barrier, or memory fence instruction, is a synchronization primitive used to solve the problem of instruction reordering in multithreading.

In modern multi-core processors, processors and compilers rearrange instructions to improve processing efficiency. This optimization is usually no problem in a single-threaded environment, but may cause problems in a multi-threaded environment. Because if two threads access a shared variable, they may see errors or inconsistent data due to instruction reordering.

At this time, we need memory barriers to solve this problem. A memory barrier forces the processor to complete all read/write operations before executing the memory barrier, and ensures that all read/write operations after the memory barrier begin only after the operations before the memory barrier have completed. In other words, memory barriers prevent instruction reordering and ensure that instructions are executed in the same order as the program.

The function of the memory barrier is to ensure that operations before it will not be queued after it, and operations after it will not be queued before it, thereby ensuring the orderliness of data and avoiding errors caused by instruction rearrangement. Data inconsistency issues.

2. Introduction to JVM Memory Model (JMM)

The memory model of the JVM, also known as the Java Memory Model (JMM), is mainly a model built around how to handle the three characteristics of atomicity, visibility, and ordering in the concurrent process.

In Java, all instance fields, static fields, and array elements are stored in heap memory and shared among multiple threads. Local variables, method definition parameters, and exception handler parameters are not shared between threads, and they do not suffer from data races.

Thread operations on these shared data must be coordinated through main memory. Threads cannot communicate directly with each other, and all reads and writes of shared data by threads must go through main memory. However, in order to improve efficiency, when reading main memory data, each thread will first copy the value of the variable to its own working memory (corresponding to the CPU's cache), then operate on these copies, and then The new value is written back to main memory.

This may cause a problem. When two threads operate a variable at the same time, one thread modifies the value of the variable, but before the new value is written back to the main memory, the other thread reads the value of the variable. This What is read at the time is the old value. That is to say, the modification of the shared variable by one thread may not be immediately visible to another thread, which involves visibility issues.

Instruction reordering may also cause threads to see inconsistent variable values. In order to improve the efficiency of instruction execution, the CPU and compiler may rearrange instructions. Without appropriate synchronization measures, instruction reordering may lead to some unexpected results, especially in multi-threaded environments.

Therefore, in order to solve the visibility and ordering issues, the Java memory model introduces mechanisms such as memory barriers to ensure the consistency and ordering of data during concurrency.

III. Memory barriers in Hotspot

Think about some questions

    1. Where does Hotspot insert memory barriers?
    1. Four types of memory barriers: LoadLoad, StoreStore, LoadStore, StoreLoad and how they work respectively
    1. How hotspot uses different types of memory barriers to implement happens-before relationships in JMM

As an implementation of Java, the HotSpot virtual machine uses memory barrier technology to ensure visibility and orderliness in the Java Memory Model (JMM). A memory barrier is a special set of CPU instructions used to prevent instruction reordering and ensure data visibility. HotSpot inserts memory barriers at key places to implement happens-before relationships in JMM.

There are four types of memory barriers:

  1. LoadLoad barrier: Ensure that all read operations before the LoadLoad barrier are completed before starting read operations behind the barrier.

  2. StoreStore Barrier: Ensure that all write operations before the StoreStore barrier are completed before writing operations behind the barrier begin.

  3. LoadStore barrier: Ensure that all read operations before the LoadStore barrier are completed before writing operations behind the barrier begin.

  4. StoreLoad barrier: Ensure that all write operations before the StoreLoad barrier are completed before reading operations behind the barrier begin.

Different types of memory barriers are used to implement the happens-before relationship in JMM as follows:

  1. For read operations on volatile variables, a LoadLoad barrier needs to be inserted before the read operation to ensure that other threads have completed writing to this variable before reading the volatile variable. At the same time, a LoadStore barrier is inserted after the read operation to ensure that the read of volatile variables is completed before subsequent write operations.

  2. For writing operations to volatile variables, a StoreStore barrier needs to be inserted before the writing operation to ensure that other threads have completed writing to this variable before writing to the volatile variable. At the same time, a StoreLoad barrier is inserted after the write operation to ensure that the writing of volatile variables is completed before subsequent read operations.

  3. For the lock release operation, a StoreStore barrier needs to be inserted before the lock is released to ensure that the writing of the shared data has been completed before the lock is released. In this way, when another thread acquires the lock, it can see the modifications made by the previous thread to the shared data.

  4. For the lock acquisition operation, a LoadLoad barrier needs to be inserted after the lock is acquired to ensure that the reading of the shared data has been completed before the lock is acquired. In this way, after the current thread acquires the lock, it can see the modifications of the shared data by the previous thread.

By inserting different types of memory barriers at key locations, the HotSpot virtual machine can ensure that data access between threads has a certain order and visibility in a multi-threaded environment, thereby realizing the happens-before relationship in JMM.

4. Example: How volatile variables use memory barriers in Hotspot

  • Write operations of volatile variables happen-before read operations of other threads
  • Hotspot inserts a StoreLoad barrier between read and write operations on volatile variables

volatileVariables have special semantics in the Java memory model, and their write operations happen-before read operations by other threads. This means that once one thread writes to a volatilevariable, subsequent threads reading the volatilevariable will see the write.

In the Hotspot virtual machine, in order to ensure volatilethe semantics of variables, volatileStoreLoad barriers are inserted after the write operation and before the read operation of the variable.

When we volatilewrite to a variable, a StoreStore barrier will be inserted after the write operation to prevent the write operation from being reordered with subsequent write operations, and to ensure that the write operation is visible to all processors. Then insert a StoreLoad barrier to prevent the reordering of write operations and subsequent read operations.

When we volatileread a variable, a LoadLoad barrier will be inserted after the read operation to prevent the reordering of the read operation and subsequent read operations and ensure that the latest data can be read. At the same time, a LoadStore barrier is inserted to prevent the reordering of read operations and subsequent write operations. This ensures that volatileall operations after reading the variable will see volatilethe latest value of the variable.

By volatileinserting a StoreLoad barrier between the read and write operations of variables, the Hotspot virtual machine can ensure that the volatilewrite operations of variables happen-before the read operations of other threads, thereby realizing volatilethe semantics of variables.
Suppose we have two threads, Thread A and Thread B. Thread A is responsible for updating a volatilevariable v, and thread B is responsible for reading this variable.

Here is the relevant code:

Thread A:

v = 1;  // 写操作
...

Thread B:

int a = v;  // 读操作
...

In the Hotspot virtual machine, in order to ensure volatile semantics, when the above code is actually executed, a memory barrier will be inserted into the following form:

Thread A:

v = 1;  // 写操作
StoreStore屏障
StoreLoad屏障
...

Thread B:

LoadLoad屏障
LoadStore屏障
int a = v;  // 读操作
...

In thread A, v = 1;the StoreStore barrier and StoreLoad barrier will be inserted later. The StoreStore barrier is used to prevent subsequent write operations from being advanced, and the StoreLoad barrier is used to prevent subsequent read operations from being advanced.

In thread B, int a = v;the LoadLoad barrier and the LoadStore barrier are inserted before the read operation. The LoadLoad barrier is used to prevent subsequent read operations from being advanced, and the LoadStore barrier is used to prevent subsequent write operations from being advanced.

In this way, the Hotspot virtual machine ensures that the write operation of the volatile variable happens-before the read operation of other threads, that is, thread B can see the update of the variable by thread vA.

5 Conclusion

  • By using memory barriers, Hotspot ensures that the compiler and processor do not perform erroneous instruction reordering of critical memory operations while respecting the happens-before relationship.
  • This allows programmers to write correct and reliable code in a multi-threaded environment

6. Reference documents

  1. oracle java JMM official documentation : https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4

Guess you like

Origin blog.csdn.net/wangshuai6707/article/details/132990014