11

Java Memory Model (JMM) interview answer, packaged!

In interviews, interviewers often like to ask: "What is the Java Memory Model (JMM)? 』

The interviewer was ecstatic, and just memorized this question: "Java memory is mainly divided into five blocks: heap, method area, virtual machine stack, local method stack, PC register, balabala..."

The interviewer smiled knowingly and revealed a ray of light: "Well, today’s interview is here first, go back and wait for the notice."

Generally speaking, when I hear the phrase "waiting for notification," the interview is likely to be cold. why? Because the interviewer made a mistake in the concept, the interviewer wanted to investigate JMM, but the interviewer started to recite the eight-legged essay as soon as he heard the keywords of Java memory. There is a big difference between the Java Memory Model (JMM) and the Java runtime memory area. Don't go away and look down. I promised me to finish.

1. Why is there a memory model?

To answer this question, we need to understand the traditional computer hardware memory architecture. Okay, I'm going to start drawing.

1.1. Hardware memory architecture

在这里插入图片描述

1)CPU

Students who have been to the computer room know that multiple CPUs are generally configured on large servers, and each CPU has multiple cores, which means that multiple CPUs or multiple cores can work at the same time (concurrently). If you use Java to start a multi-threaded task, it is very likely that each CPU will run a thread, then your task will be executed concurrently at a certain moment.

(2)CPU Register

CPU Register is also CPU register. The CPU registers are integrated inside the CPU, and the efficiency of performing operations on the registers is several orders of magnitude higher than on the main memory.

(3)CPU Cache Memory

CPU Cache Memory is also the CPU cache. Compared with the register, it can usually become the L2 second-level cache. Compared with the hard disk read speed, the memory read efficiency is very high, but it is still orders of magnitude different from the CPU, so a multi-level cache is introduced between the CPU and the main memory for the purpose of buffering.

(4)Main Memory

Main Memory is the main memory, which is much larger than the L1 and L2 caches.

Note: Some high-end machines also have L3 level three cache.

1.2. Cache consistency issues

Because there is an order of magnitude difference between the computing power of the main memory and the CPU processor, a cache is introduced in the traditional computer memory architecture as a buffer between the main memory and the processor, and the CPU puts commonly used data in the cache. , After the calculation is completed, the CPU will synchronize the calculation result to the main memory.

The use of high-speed cache solves the problem of the mismatch between CPU and main memory rates, but at the same time introduces another new problem: the problem of cache coherency.
在这里插入图片描述

In a multi-CPU system (or a single-CPU multi-core system), each CPU core has its own cache, and they share the same Main Memory. When the calculation tasks of multiple CPUs involve the same main memory area, the CPU will read data into the cache for calculations, which may cause inconsistencies in their respective cache data.

Therefore, each CPU needs to follow a certain protocol when accessing the cache, and operate according to the protocol when reading and writing data, to jointly maintain the consistency of the cache. Such protocols include MSI, MESI, MOSI, and Dragon Protocol.

1.3. Processor optimization and instruction reordering

In order to improve performance, a cache is added between the CPU and the main memory, but in a multi-threaded concurrency scenario, cache coherency may be encountered. Is there any way to further improve the execution efficiency of the CPU? The answer is: processor optimization.

In order to maximize the full utilization of the arithmetic unit inside the processor, the processor performs out-of-order execution processing on the input code, which is processor optimization.

In addition to the processor's optimization of the code, many modern programming language compilers will also do similar optimizations, such as Java's just-in-time compiler (JIT), which will do instruction reordering.
在这里插入图片描述

Processor optimization is actually a type of reordering. To summarize, reordering can be divided into three types:

  • Compiler optimized reordering. The compiler can rearrange the execution order of statements without changing the semantics of single-threaded programs.
  • Instruction-level parallel reordering. Modern processors use instruction-level parallel technology 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.

2. The problem of concurrent programming

I talked about a bunch of hardware-related things above. Some students may be a little confused. After going around such a big circle, do these things have anything to do with the Java memory model? Don't worry, let's look down slowly.

Students who are familiar with Java concurrency must be familiar with these three issues: "visibility issues", "atomic issues", and "order issues". If you look at these three problems from a deeper level, they are actually caused by the "cache coherency", "processor optimization", and "instruction reordering" mentioned above.

在这里插入图片描述

The cache coherency problem is actually a visibility problem. Processor optimization may cause atomicity problems, and instruction reordering will cause ordering problems. Do you think they are all connected?

When there is a problem, it is always necessary to solve it, so what can be done? First of all, I thought of a simple and rude way. The visibility problem was solved by eliminating the cache and allowing the CPU to directly interact with the main memory. Disabling processor optimization and instruction reordering solved the problem of atomicity and ordering, but it was back to before liberation overnight. , Obviously undesirable.

So the technical predecessors thought of defining a set of memory models on physical machines to standardize memory read and write operations. The memory model mainly uses two ways to solve the concurrency problem: limiting processor optimization and using memory barriers.

3. Java Memory Model

The same set of memory model specifications, different languages may have some differences in implementation. Next, I will focus on the implementation principle of the Java memory model.

3.1. The relationship between Java runtime memory area and hardware memory

Anyone who knows the JVM knows that the memory area of the JVM is sharded when it is running, divided into stacks, heaps, etc. In fact, these are logical concepts defined by the JVM. In the traditional hardware memory architecture, there is no concept of stack and heap.
在这里插入图片描述

It can be seen from the figure that the stack and the heap exist in both the cache and the main memory, so there is no direct relationship between the two.

3.2. The relationship between Java threads and main memory

The Java memory model is a specification that defines many things:

  • All variables are stored in the main memory (Main Memory).
  • Each thread has a private local memory (Local Memory), where the thread is stored in the local memory to read/write a copy of the shared variable.
  • All operations of threads on variables must be performed in local memory, and cannot directly read or write to main memory.
  • Different threads cannot directly access the variables in each other's local memory.

It's too boring to read the text, so I drew another picture:
在这里插入图片描述

3.3. Communication between threads

If two threads both operate on a shared variable, the initial value of the shared variable is 1, and each thread increments the variable by 1, and the expected value of the shared variable is 3. There will be a series of operations under the JMM specification.
在这里插入图片描述

In order to better control the interaction between main memory and local memory, the Java memory model defines eight operations to achieve:

  • lock: locked. A variable acting on the main memory identifies a variable as a thread exclusive state.
  • unlock: unlock. Act on the main memory variable, release a variable that is in a locked state, and the released variable can be locked by other threads.
  • read: read. Act on the main memory variable, transfer a variable value from the main memory to the thread's working memory for use in subsequent load actions
  • load: load. Acting on the variable of the working memory, it puts the variable value obtained from the main memory by the read operation into the variable copy of the working memory.
  • use: Use. Acting on the variable of the working memory, the value of a variable in the working memory is passed to the execution engine, and this operation will be executed whenever the virtual machine encounters a bytecode instruction that needs to use the value of the variable.
  • assign: Assignment. The variable acting on the working memory, it assigns a value received from the execution engine to the variable of the working memory, and executes this operation whenever the virtual machine encounters a bytecode instruction that assigns a value to the variable.
  • store: store. The variable acting on the working memory transfers the value of a variable in the working memory to the main memory for subsequent write operations.
  • write: write. Acting on a variable in the main memory, it transfers the value of a variable in the working memory to a variable in the main memory from the store operation.
Note: Working memory also means local memory.

4. Summary with attitude

Due to the order of magnitude speed difference between the CPU and the main memory, the traditional hardware memory architecture that introduces a multi-level cache was thought of to solve it. The multi-level cache acts as a buffer between the CPU and the main memory to improve the overall performance. Solved the problem of poor speed, but brought about the problem of cache coherence.

Data exists in both the cache and main memory at the same time. If it is not standardized, it will inevitably cause disasters. Therefore, the memory model is abstracted on traditional machines.

The Java language introduced the JMM specification based on the memory model. The purpose is to solve the inconsistency of local memory data when multiple threads communicate through shared memory, the compiler will reorder the code instructions, and the processor will disorder the code. Problems caused by implementation, etc.

In order to more precisely control the interaction between the working memory and the main memory, JMM also defines eight operations: lock, unlock, read, load, use, assign, store, write.

This is the end of the Java Memory Model (JMM) interview answer! Have you passed?


老刘
45 声望3 粉丝