Learning Java Memory Model JMM experience
Sometimes, the optimization of compiler and processor will cause the runtime to be different from what we think. Therefore, Java has made some restrictions on compiler and processor, which are abstracted by Java Memory Model (JMM), so that there is no need to consider so many underlying details when writing code, and ensure that "as long as the program is written according to JMM's rules, its running result must be correct".
Abstract structure of JMM
In Java, all instances and static variables are stored in heap memory, which can be shared between processes. This part is also called shared variables. Local variables, method definition parameters and exception handling parameters are in the stack, and the stack memory is not shared between processes.
The optimization of compilers and processors will lead to visibility problems of shared variables. For example, in multi-core processors, threads can execute on different processors, and inconsistent caches between processors will lead to visibility problems of shared variables. It is possible that two threads see different values of the same variable.
JMM abstracts the optimization of these hardware into that each thread has a local memory. When you need to read and write shared variables, copy a copy from main memory to local memory. When writing shared variables, first write them to local memory and then refresh them to main memory at a certain time in the future. When the shared variable is read again, it will only be read from local memory.
In this way, the communication between threads needs to go through two steps:
Write thread: refresh the local memory to the main memory. Read thread: read the updated value from the main memory
Thus, there is a delay between write and read: when will the local memory be flushed to the main memory? This leads to visibility problems. Different threads may see different shared variables.
happens-before
Literally, happens before means "before". This is a rule formulated by Java for program execution sequence, which must be followed to realize synchronization. In this way, the programmer only needs to write the correct synchronization program to ensure that the running result will not be wrong.
A happens before B not only means that a executes before B, but also means that the execution result of a is visible to B, which ensures visibility.
A happens before B. A does not have to be executed before B. If AB alternates and the execution result is still correct, the compiler and processor are allowed to optimize and reorder. So as long as the program results are correct, how to optimize the compiler and processor and how to reorder are all good.
Happens before rule
Program sequence rules: in a thread, the previous operation happens before and the subsequent operation lock rules: Unlock the happens before and lock the same lock. Volatile domain rules: write the volatile variable. The transitivity of any operation after happens before to read the volatile variable: a happens before B, B happens before C, Then a happens before C start() rule: if thread a executes threadb Start() then threadb Start() happens before any operation in thread B join() rule: if thread a executes threadb Join(), then all operations in thread B will happen before threadb join()
The following example is helpful to understand happens before
There are three happens before relationships. Rules 1 and 2 are program sequence rules, and rule 3 is derived from transitive rules:
A happens-before B B happens-before C A happens-before C
C depends on a and B, but a and B depend on no one. Therefore, even if a and B are reordered, the execution results will not change. JMM runs this reordering.
The results of the following two execution sequences are correct.
The above is all about the learning experience of Java Memory Model JMM. You can leave a message below to discuss more questions. Thank you for your support for programming tips.