A junior programmer with two years of experience trying to understand the JVM memory model, thorough!

All programming languages ​​have the concept of memory model, which is different from the memory model of micro-architecture. The memory model of high-level language includes two parts: compiler and micro-architecture. I tried to understand the memory models of Java, C#, and Go, and found that the content is basically the same, but these languages ​​are slightly different in their implementation.

Let's take a look at the Java memory model. When it comes to the Java memory model, everyone must be very familiar with this picture:

Insert picture description here

This picture tells us that there is a small piece of memory dedicated to memory when the thread is running. When the Java program synchronizes the variable to the memory where the thread is located, it will operate the variable in the working memory at this time, and the value of the variable in the thread Synchronizing back to main memory is unpredictable. But at the same time, the Java memory model tells us that by using the keywords "synchronized" or "volatile", Java can guarantee certain constraints:

"Volatile"-ensure that all reads and writes are variables of the main memory "synchronized"-ensure that the value of the main memory is synchronized to the working memory at the beginning of the block, and the variables are synchronized back to the main memory at the end of the block

Through the above description we can write thread-safe Java programs, and the JDK also helps us shield a lot of low-level things.

But when you understand the JVM deeply, you will find that there is no working memory at all, that is, there is no such a space allocated in the memory to run your Java programs, so what exactly is working memory?

This problem has troubled me for a long time, because I have never found a code that synchronizes with the main memory from the implementation of JVM, because when using "volatile" I can only call this line of statements from the source code:

__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");

The main function of this instruction in some microarchitectures is to prevent instruction rearrangement, that is, other instructions before and after this instruction will not be executed beyond this limit [Note 1].

In the current x86/x64 microarchitecture, the consistency of reading and writing memory is guaranteed by the MESI (Intel uses MESI-F, AMD uses MOESI) protocol [Note 2], the state transition diagram of MESI is as follows:

Insert picture description here

What is the working memory mentioned in the Java memory model? My understanding is that first of all, "working memory" is a virtual concept, and the concept of carrying is mainly two parts:

1. 编译器
2. 微架构

As a compiler, the faster the execution speed, the better, so as a compiler, you should minimize reading data from memory. If a data is in a register, then directly using the value in the register is undoubtedly the highest performance, but at the same time it will also lead to You may not be able to read the latest value. Here we add "volatile" to the variable in the Java language to force the compiler to tell the compiler that the variable must be obtained from memory, and then the compiler will not make such optimizations [see References for the case 5 (is an example of .Net)].

For the micro-architecture, under x86/x64, the CPU will rearrange instructions when executing instructions, that is, the order of instructions generated by the compiler and the order of actual execution on the CPU may be inconsistent. This kind of instruction rearrangement will bring tragedy when we use a variable as a signal, that is, if we have the following code:

x = 0;
y = 0;
i = 0;
j = 0;
// thread A
y = 1;
x = 1;
// thread B
i = x;
j = y;

What are the values ​​of i and j in the above code? The answer is: "00, 01, 10, 11" are all possible. In this case, if we want to get definite results, we need to synchronize between threads through "synchronized" (or jculocks).

Therefore, my personal understanding of the Java memory model is: on the various optimizations of the compiler and various types of micro-architecture platforms, the Java language specification makers try to create a virtual concept and pass it to Java programmers so that they can This virtual concept writes a thread-safe program, and the compiler implementer will achieve the goal of thread safety required by Java programmers on different platforms according to various constraints in the Java language specification.

At last

Reply to the data by private message to receive a summary of Java interview questions from a major manufacturer + Alibaba Taishan manual + a learning guide for knowledge points + a summary of Java core knowledge points in a 300-page pdf document!

The content of these materials are all the knowledge points that the interviewer must ask during the interview. The chapter includes many 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. file

Guess you like

Origin blog.csdn.net/weixin_46577306/article/details/107847710