Java memory model

Briefly introduce the Java memory model

Java Memory Model is Java Memory Model, referred to as JMM. JMM defines how the Java Virtual Machine (JVM) works in computer memory (RAM). JVM is the virtual model of the entire computer, so JMM belongs to JVM.

The Java memory model is a concurrent model of shared memory. The threads mainly complete implicit communication through read-write shared variables (instance domains, static domains and array elements in the heap memory). The Java Memory Model (JMM) controls the communication between Java threads and determines when one thread's writes to shared variables are visible to another thread.

JVM main memory and working memory

The main goal of the Java memory model is to define the access rules for each variable in the program, that is, to store variables (variables shared by threads) in the virtual machine and take out the low-level details of variables from the memory.

The Java memory model stipulates that all variables are stored in the main memory. Each thread has its own working memory. All operations on variables by the thread must be performed in the working memory, instead of directly reading and writing variables in the main memory. . The working memory here is an abstract concept of JMM, also called local memory, which stores a copy of the thread to read/write shared variables.

Just as each processor core has its own private cache, each thread in JMM has its own private local memory. Different threads cannot directly access variables in each other's working memory. Communication between threads is generally carried out in two ways, one is through message passing, and the other is shared memory. The communication between Java threads uses shared memory, and the interaction between threads, main memory, and working memory is shown in the following figure:

Thread A and thread B communicate through two steps:

Thread A flushes the updated shared variables in local memory A to main memory
Thread B goes to main memory to read the shared variable that thread A has updated before
The main memory, working memory, and the Java heap, stack, method area, etc. in the Java memory area mentioned here are not the same level of memory division. The two are basically irrelevant. If the two must be reluctantly corresponded From the definition of variables, main memory, and working memory, the main memory mainly corresponds to the object instance data part in the Java heap, and the working memory corresponds to a part of the virtual machine stack.

JMM data atomic operation

read: read data from main memory
load: write the data read from the main memory into the working memory
use (use): read data from the working memory to calculate
assign (assignment): Re-assign the calculated value to the working memory
store: Write working memory data to main memory
write (write): assign the value of the variable in the store to the variable in the main memory
lock: lock the main memory variable and mark it as a thread exclusive state
unlock (unlock): unlock the main memory variable, after unlocking other threads can lock the variable

public class VolatileVisibilityTest {

    private static volatile boolean initFlag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("waiting data...");
                while (!initFlag) {
                }
                System.out.println("====================success");
            }
        }).start();

        Thread.sleep(2000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                prepareDate();
            }
        }).start();
    }

    public static void prepareDate() {
        System.out.println("preparing data...");
        initFlag = true;
        System.out.println("prepare end...");
    }
}

Computer cache and cache coherency

Computers use high-speed caches between the high-speed CPU and relatively low-speed storage devices as a buffer between the memory and the processor. Copy the data needed for the operation to the cache, so that the operation can run quickly, and then synchronize it from the cache back to the memory when the operation is over.

In a multi-processor system (or a single-processor multi-core system), each processor core has its own cache, and they share the same main memory (Main Memory). When the computing tasks of multiple processors all involve the same main memory area, it may lead to inconsistent cache data.

For this reason, each processor needs to follow some protocols when accessing the cache, and operate according to the protocol when reading and writing to maintain the consistency of the cache.

MESI cache coherency protocol: multiple CPUs read the same data from the main memory to their respective notification caches. When one of the CPUs modifies the data in the cache, the data will be synchronized to the main memory immediately, and other CPUs will sniff through the bus The mechanism can sense the change of data and invalidate the data in its own cache.

Implementation principle of volatile cache visibility

The underlying implementation is mainly through the assembly of the lock prefix instruction, which will lock the cache of this memory area (cache line lock) and write back to the main memory

1) The data of the current processor cache line will be immediately written back to the system memory
2) This operation of writing back to the memory will cause the data cached at the memory address in other CPUs to be invalid (MESI)

Reordering and happens-before rules

In order to improve performance during program execution, compilers and processors often reorder instructions. There are three types of reordering:

Compiler optimized reordering. The compiler can rearrange the execution order of statements without changing the semantics of a single-threaded program.
Instruction-level parallel reordering. Modern processors use instruction-level parallelism (Instruction-Level Parallelism, ILP) to overlap multiple instructions. If there is no data dependency, the processor can change the execution order of the statements corresponding to the machine instructions.
Reordering of the memory system. Because the processor uses caches and read/write buffers, this makes load and store operations appear to be performed out of order.
From the java source code to the final instruction sequence actually executed, the following three kinds of reordering will be experienced respectively:

JMM is a language-level memory model, which ensures that on different compilers and different processor platforms, it provides programmers with consistent memory visibility guarantees by prohibiting specific types of compiler reordering and processor reordering. The java compiler's prohibition of processor reordering is achieved by inserting a memory barrier at the appropriate position of the generated instruction sequence (the following instructions cannot be reordered to the position before the memory barrier during reordering) instructions.

happens-before

Starting from JDK5, the java memory model puts forward the concept of happens-before, through which the memory visibility between operations is explained. If the result of one operation needs to be visible to another operation, then there must be a happens-before relationship between the two operations. The two operations mentioned here can be within one thread or between different threads. "Visibility" here means that when a thread modifies the value of this variable, the new value is immediately known to other threads.

If A happens-before B, then the Java memory model will assure the programmer-the result of the operation of A will be visible to B, and the order of execution of A will be before B.

The important happens-before rules are as follows:

Program sequence rules: For each operation in a thread, happens- before any subsequent operations in the thread.
Monitor lock rule: To unlock a monitor lock, happens- before and then lock the monitor lock.
Volatile variable rules: write to a volatile domain, happens- before any subsequent reads of this volatile domain.
Transitivity: If A happens- before B, and B happens- before C, then A happens- before C.
The following figure shows the relationship between happens-before and JMM

At last

At the end of the article, the author has compiled a lot of information for everyone! Including a summary of the Java interview questions of the first-line manufacturers + the learning and thinking guide of each knowledge point + a summary of the Java core knowledge points of a 300-page pdf document! The content of these materials are all knowledge points that the interviewer must ask during the interview. The chapter includes a lot of knowledge points, including basic knowledge, Java collections, JVM, multi-threaded concurrency, spring principles, microservices, Netty and RPC, Kafka , Diary, design pattern, Java algorithm, database, Zookeeper, distributed cache, data structure, etc.
Welcome to pay attention to the official account: have a bright future, get it!


前程有光
936 声望618 粉丝