What is JMM?

I interviewed many candidates as an interviewer last year. I know that many people have not figured out the concept and role of Java's memory model. When I asked about Java's memory model, most of them were Answered what the memory structure of the JVM, that is, the heap, these are all wrong, then what is the actual Java memory model? What are its frequently asked interview questions? Don't worry, I have already arranged it for you.
Understand a few important concepts. We all know that
CPU and cache coherence
, when a computer executes a program, every instruction is executed in the CPU, and when executing, it is inevitable to deal with data, and the data on the computer is stored in the computer's physical On the memory.
When the read speed of the memory is not much different from the execution speed of the CPU, there is no problem with such a mechanism, but with the development of CPU technology, the gap between the execution speed of the CPU and the read speed of the memory is getting bigger and bigger. The larger it is, the CPU will consume a lot of waiting time each time it operates the memory.
In order to solve this problem, the first generation of programmers thought of a way, which is to add a high-speed cache to the CPU and physical memory, so that the execution process of the program has also changed, and it becomes the program in the process of running. Copy the data needed for the operation from the main memory to the CPU's cache. When the CPU is performing calculations, you can directly read and write data from the cache. When the operation is over, refresh the data to the main memory. Up.
As the times change and programmers become more capable, the concept of multi-core CPUs began to appear. Each core has its own set of caches. With the continuous improvement of computer capabilities, it also began to support multi-threading, which eventually evolved into multiple If a thread accesses a shared memory in the process, and these multiple threads are executed on different cores, each core will reserve a shared memory buffer in its own Cache. We know that multiple cores can be parallelized, so There will be situations where multiple threads write to their respective caches at the same time, resulting in different data between the respective Caches.
The summary is: in a multi-core CPU, the cache content of each core may be inconsistent with respect to the same data.
Processor optimization and instruction rearrangement
In order to make full use of the arithmetic unit inside the processor, the processor may perform out-of-order execution processing on the program code. This is processor optimization.
In addition to many popular processors that optimize out-of-order processing of codes, compilers of many programming languages ​​will also have similar optimizations. For example, the Just-in-Time Compiler (JIT) of the Java Virtual Machine will also perform instruction rearrangement.
It is conceivable that if the processor optimization and the compiler are allowed to rearrange the instructions, it may cause various problems.
What problems does concurrent programming bring? The
hardware-related concepts mentioned above may sound a bit confusing to me. Most of them are software engineers, but we should know something about concurrent programming, such as Familiar atomicity issues, visibility issues, and order issues.
In fact, atomicity issues, visibility issues, and order issues are concepts abstracted by the first generation of program tycoons later, which correspond to the aforementioned cache coherence issues, processor optimization issues, and instruction rearrangement issues, etc. , I have to say that the first-generation program tycoons took great pains to let us software engineers understand the concept of hardware.
In order to ensure data security, concurrent programming must meet the following three characteristics:

Atomicity refers to the fact that the CPU cannot be suspended in the middle of an operation and then scheduled again, or it is not executed or the execution is completed.
Visibility refers to the fact that when multiple threads access the same variable, one thread modifies the value of this variable, and other threads can immediately see the modified value.
Orderliness means that the order in which the program is executed is executed in the order of the code, and cannot be rearranged several times, resulting in inconsistent results in the program.

After reading the explanation of the three features above, we can also know that the cache coherency problem is actually a visibility problem, and processor optimization can cause atomic problems, and instruction rearrangement can cause order problems.
The summary is: concurrent programming will bring about atomicity problems, visibility problems, and ordering problems.
What is the memory model? The
cache coherence problem mentioned above is actually caused by the continuous upgrade of hardware. Some big-hearted friends may To put it straight, abolish the processor and processor optimization technology, abolish the CPU cache, and let the CPU directly interact with the main memory, isn't it okay?
First of all, the idea is affirmative and it can be solved, but the approach is a bit too much, which is equivalent to abandoning the car directly in order to avoid a car accident.
In order to ensure that concurrent programming can meet atomicity, visibility and order, Java has born an important concept, that is, the memory model, which defines the specification of the read and write operations of multithreaded programs in the shared memory system.
These rules are used to regulate the read and write operations to the memory to ensure the correct execution of instructions. It solves the memory access problems caused by CPU multi-level cache, processor optimization, instruction rearrangement, etc., and ensures consistency in concurrent scenarios , Atomicity and Orderliness.
The summary is: the Java memory model defines the specification of the read and write operations of multithreaded programs in the shared memory system, and the Java memory model exists to solve this concurrent programming problem.
How does the memory model solve the concurrency problem?
The memory model mainly adopts two ways to solve the concurrency problem, one is to limit processor optimization, and the other is to use a memory barrier.
For these two methods, some keywords have been encapsulated at the bottom of Java, and we only need to use them here.
Regarding solving the atomicity problem in concurrent programming, the bottom layer of Java encapsulates the Synchronized method to ensure that the methods and operations in the code block are atomic;
As for the visibility issue, the bottom layer of Java encapsulates the Volatile approach, which synchronizes the modified variable to the main memory immediately after modification.
As for the ordering problem, it is actually what we call the reordering problem. The Volatile keyword also prohibits the reordering of instructions, and the Synchroinzed keyword guarantees that only one thread operation is allowed at the same time, which naturally guarantees order. Sex.
Summarize the wave: When you see this, you should basically understand what JMM is and what it is used for. The above explanation should be very clear and easy to understand. If you still don’t understand it, read it twice to understand JMM. What is too important for concurrent programming.
Share a few common interview questions

Tell me about the communication mechanism between threads? What kind of concurrency does Java use?

The communication mechanism between threads can be divided into two types, namely

Shared memory
messaging

Currently, concurrent communication in Java uses a shared memory method.
This question is a relatively common theoretical question. Some people know a little about the operating system and know that there are two communication mechanisms between threads, but few people know that Java's concurrent communication uses a shared memory method.

Yes, you know that Java threads communicate through shared memory is the first step to understand the memory model. Let’s talk about your understanding of the memory model, right?

Is the memory model? What is the memory model of JVM? Or is it the Java memory model, or JMM?
This question is more confusing. Most people think of the JVM memory model first when they hear the memory model, that is, the heap memory. So if you encounter a problem with unclear concepts, you must be bold. Remember when I just graduated. Once I heard this kind of problem, I misunderstood that it was the JVM memory model that caused the loss of points.

It is the Java memory model, which is JMM, what do you think is the memory model? What is the role?

JMM does not actually exist like the JVM memory model, it is just an abstract specification. Under different hardware or operating systems, there are certain differences in the memory access logic, and this difference will cause the same set of code to obtain different results under different operating systems or hardware, and the existence of JMM is to solve This problem, through the JMM specification, guarantees that Java programs can get consistent effects on memory access under various platforms.
The concept of JMM is actually easier to forget, so I specifically stated here that it exists to solve the above problems. By understanding what it is and what it is used for, it is easier to generate deep memory.

Well, yes, talk about the division of memory in JMM?

JMM stipulates that the memory is mainly divided into main memory and working memory. All variables are stored in the main memory. Each thread has its own working memory. The working memory of the thread stores the variables used in the thread. A copy of the main memory of the thread, all operations on variables by the thread must be performed in the working memory, and the main memory cannot be directly read and written.
Different threads cannot directly access the variables in each other's working memory. The transmission of variables between threads requires data synchronization between their own working memory and main memory.

Insert picture description here
In order to clearly show this process, I specially drew a picture

The picture is good, what do you mean by the working memory and main memory?

The working memory and main memory here are actually divided from the JVM memory at different levels. It is a set of abstract concepts of its own. It can be understood that the main memory corresponds to the object instance part in the Java heap, and the work The memory corresponds to a part of the stack,

Tell me about what operations JMM defines to complete the interactive operation of main memory and working memory?

JMM defines 8 operations to complete the interaction between the main memory and the working memory. The first is to start with the lock and mark the variable in the main memory as a thread exclusive state; read reads the value of a variable from the main The memory is transferred to the working memory; load is loaded, the value obtained by read is loaded into the variable copy of the working memory; the use is used, the value of the variable in the working memory is passed to the execution engine; the assign is assigned, the value received from the execution engine The variable assigned to the working memory; store storage, transfer the value of the variable in the working memory back to the main memory; write write, put the value obtained by the store into the variable of the main memory; finally unlock unlock, put the main memory in When the locked variable is released, the process ends at this step.

Insert picture description here
Yes, the process is relatively clear. Tell me about the understanding of the three characteristics of the basic operation of memory interaction?

JMM can basically be said to be built around how to deal with these three characteristics in concurrency, that is, atomicity, visibility, and order.
The so-called atomicity means that an operation or multiple operations are either all executed and the execution process will not be interrupted by any factor, or not executed.
**Expansion:** We all know that the CPU has the concept of time slices, and thread scheduling is performed according to different scheduling algorithms. When a thread is performing a read/write operation, after the read/write operation is completed, the time slice is exhausted. Will be asked to give up the CPU and wait for rescheduling. In this case, read/write is not an atomic operation, that is, there is an atomic problem.
Visibility means that when multiple threads access the same variable, one thread modifies the value of this variable, and other threads can immediately see the modified value.
**Extension:** When multiple threads access a shared memory in a process, these multiple threads are executed on different CPUs, and each CPU will keep a shared memory buffer in its own cache. Because multiple cores can be parallelized, multiple threads may write to their respective caches at the same time, and the data between the respective caches may be different, which presents a visibility problem.
Ordering means that the order of program execution is executed in the order of code.
**Expansion: **Due to processor optimization and instruction rearrangement and CPU may also perform out-of-order execution of input code, such as load->add->save may be optimized to load->save->add, this is Order issues.
In the final analysis, it is to achieve the data consistency of the working memory of multiple threads, so that the program can execute as expected in an environment with multi-thread concurrency and instruction reordering optimization.
The vernacular explained a wave of atomicity issues, visibility issues, and order issues. Also, remember the concepts first, and then understand and expand. That’s enough, there are no pitfalls. The concept part is required, while the expansion part is actually a bonus item. We interviewers like candidates to have their own opinions on the answers, instead of memorizing various answers. Without their own opinions, they can only be regarded as mediocre. .

Take a look, which of the following operations are atomic operations?

a = 20;
b = a;
Copy code
Except for the first operation, the others are non-atomic operations.
Many people here may not understand why the second operation is a non-atomic operation. In fact, the second operation contains two parts. It first reads the value of a, and then writes the value of a to b. Although reading the value of a and writing the value of a into the working memory are two atomic operations, they are not atomic operations together.

Yes, how does Java guarantee atomic operations?

JMM only guarantees that basic reading and assignment are atomic operations, but if you want to achieve atomicity of a larger range of operations, you can achieve it through synchroinzed and lock. Synchronized and lock can ensure that only one thread executes the code at any time Block, thereby ensuring atomicity.

Do you talk about what Java uses to ensure visibility?

For visibility, Java provides the volatile keyword to ensure visibility, while synchronized and lock can also ensure visibility. Synchronized and lock can ensure that only one thread acquires the lock at the same time and then executes the synchronization code, and it will be executed before the lock is released. The changes to the variables are flushed to the main memory, so visibility can be guaranteed.

Talk about how volatile takes effect?

When a shared variable is modified by volatile, it will ensure that the modified value is immediately updated to the main memory. When other threads read the value, it will not directly read the value in the working memory, but go directly to the main memory. Read from memory.
The visibility of ordinary shared variables cannot be guaranteed, because after ordinary shared variables are modified, they are written to the working memory. When the write to the main memory is actually unknown, when other threads read it, no matter what Whether it is working memory or main memory, it may still have the original value, so visibility cannot be guaranteed.

Talk about how Java guarantees orderliness?

First of all, in Java, you can use synchronized and lock to ensure order. Synchronized and Lock can ensure that one thread executes the synchronization code at every moment, which is equivalent to allowing threads to execute the synchronization code in order, which naturally ensures order. .
In addition, the Java memory model also guarantees order through the happens-before principle.

Yes, the understanding of the three characteristics is unique. You just mentioned the happens-before principle. Tell me about your understanding of it?

This level is more complicated and difficult to describe. In order to clearly describe the process to the interviewer, I gave an example and added that there are two operations in the program, namely A and B;

Insert picture description here
First of all, these two operations can be executed within one thread, or between different threads;
and if it is single-threaded, the compiled bytecode naturally includes the happens-before relationship, because single-threaded There is no problem of data consistency by sharing a working memory within. The first bytecode in the program control flow path happens-before the later bytecode, that is, the result of the operation after the execution of the earlier bytecode is visible to the later bytecode.
Of course, this does not mean that the former must be executed before the latter. In fact, if the latter does not depend on the results of the former, they may be reordered.
If it is multi-threaded, since each thread has a copy of the shared variable, if the shared variable is not synchronized, after thread 1 updates the value of the shared variable of operation A, thread 2 starts to execute operation B. This When the result of operation A is not necessarily visible to operation B.
In order to solve this multi-threaded development problem and facilitate program development, JMM provides our programmers with cross-thread memory visibility guarantees through the happens-before relationship, that is to say, if there is a gap between the A operation of thread 1 and the B operation of thread 2 The happens-before relationship. Although the A operation and the B operation are executed in different threads, JMM still guarantees to our programmers that the A operation is visible to the B operation.

Well, according to your answer, does the existence of JMM restrict reordering at the same time?

no. Although JMM defines that if one operation happens-before another operation, then the execution result of the first operation will be visible to the second operation, but this does not mean that the specific implementation of the Java platform must be in the order specified by the happens-before relationship Execution, if the execution result after reordering is consistent with the result of executing according to the happens-before relationship, then this reordering is not illegal, that is, JMM allows this reordering.
Extension: We must remember that JMM is actually following a basic principle, that is, as long as the execution result of the program is not changed, whether it is single-threaded or multi-threaded, the compiler and processor can be optimized. In fact, the reason why JMM can do this is also very simple. After all, we don’t care about whether these two operations are really reordered in our development. What we care about is that the execution result of the program cannot be changed, that is, as long as there is no bug. , Crying.

Reference: "2020 latest Java basics and detailed video tutorials and learning routes!

Original link: https://juejin.cn/post/6919129152079527950

Guess you like

Origin blog.csdn.net/weixin_46699878/article/details/112907568