Java memory model related

Talk about JMM (Java Memory Model)?

JMM is the Java Memory Model, also known as Java Memory Model, JMM for short. It is an abstract concept in itself and does not actually exist. It describes a set of rules or specifications through which each variable in the program is defined ( Including instance fields, static fields and the elements that make up the array object) access methods.

JMM regulations on synchronization:

  • Before the thread is unlocked, the value of the shared variable must be flushed back to the main memory
  • Before the thread is unlocked, it must read the latest value of the main memory to its own working memory
  • Locking and unlocking are the same lock

Since the entity of the JVM running program is a thread, and each thread is created, the JVM will create a working memory for it (some places become stack space). The working memory is the private data area of ​​each thread, and all variables are specified in the Java memory model. All are stored in the main memory, the main memory is a shared memory area, all threads can access, but the thread's operations on variables (read assignment, etc.) must be performed in the working memory. First, the variables must be copied from the main memory to their own work. Space, and then operate on the variables. After the operation is completed, the variables are written back to the main memory. The variables in the main memory cannot be directly manipulated. The working memory in each thread stores a copy of the variable in the main memory, so different threads cannot access each other. The working memory of this case must be completed through the main memory. The brief access process is as follows:

Insert picture description here

Do you know ThreadLocal? what's the effect? Do you know the principle? Have you encountered ThreadLocal memory leaks?

https://blog.csdn.net/weixin_44533129/article/details/113111127

What is instruction reordering? Do you know what happens-before? Do you know the semantics of as-if-serial?

Reordering refers to a means by which the compiler and processor reorder the instruction sequence in order to optimize the performance of the program.
How to solve instruction reordering: https://blog.csdn.net/weixin_44533129/article/details/111658481

Definition of happens-before relationship:

  • If one operation happens-before another operation, then the execution result of the first operation will be visible to the second operation, and the execution order of the first operation is arranged before the second operation.
  • The happens-before relationship between the two operations does not mean that the specific implementation of the Java platform must be executed in the order specified by the happens-before relationship. If the execution result after reordering is consistent with the result of executing the happens-before relationship, then this kind of reordering is not illegal (that is, JMM allows this kind of reordering)

The happens-before rule:

  • Program sequence rules: For each operation in a thread, happens-before any subsequent operations in the thread.
  • Monitor lock rule: to unlock a lock, happens-before and then lock the 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.
  • Start() rule: If thread A performs the operation ThreadB.start() (start thread B), then the ThreadB.start() operation of thread A happens-before any operation in thread B.
  • The join() rule: If thread A performs the operation ThreadB.join() and returns successfully, then any operation in thread B happens-before that thread A successfully returns from the ThreadB.join() operation.

as-if-serial semantics:
as-if-serial semantics means: no matter how reordering (compiler and processor in order to improve the degree of parallelism), the execution result of the (single-threaded) program cannot be changed.

What is false sharing? How to solve?

What is false sharing?

In order to solve the problem of the operating speed difference between the main memory and the CPU in the computer system, one or more levels of cache memory (Cache) will be added between the CPU and the main memory. This Cache is generally integrated into the CPU, so it is also called CPU Cache. The following figure shows a two-level Cache structure.
Insert picture description hereInside the Cache, it is stored in rows, and each row is called a Cache row. The Cache line (as shown in the figure below) is the unit of data exchange between the Cache and the main memory. The size of the Cache line is generally a power-of-two byte.
Insert picture description here
When the CPU accesses a variable, it will first check whether there is the variable in the CPU Cache, if there is it, get it directly from it, otherwise it will get the variable in the main memory, and then set the size of a Cache line in the memory area where the variable is located. The memory is copied to the Cache. Because the memory block is stored in the Cache line instead of a single variable, it is possible to store multiple variables in a Cache line. When multiple threads modify multiple variables in a cache line at the same time, since only one thread can operate the cache line at the same time, the performance will be reduced compared to putting each variable in a cache line, which is pseudo sharing ,As shown below.
Insert picture description here

In this figure, variables x and y are placed in the primary and secondary caches of the CPU at the same time. When thread 1 uses the CPU to update variable x, it will first modify the cache line where the primary cache variable x of CPU1 is located. At this time, under the cache coherency protocol, the cache line corresponding to the variable x in CPU2 becomes invalid. Then thread 2 can only look in the second-level cache when writing variable x, which destroys the first-level cache. The first level cache is faster than the second level cache, which also shows that multiple threads cannot modify the variables in the same cache line in the CPU they are using at the same time. To make matters worse, if the CPU has only a first-level cache, it will cause frequent access to the main memory.

How to avoid false sharing:

Before JDK8, this problem was generally avoided by byte padding, that is, when a variable is created, the padding field is used to fill the cache line where the variable is located, so as to avoid storing multiple variables in the same cache line

JDK8 provides a sun.misc.Contended annotation to solve the problem of false sharing.

Guess you like

Origin blog.csdn.net/weixin_44533129/article/details/113104947