Arrangement of basic knowledge of Java virtual machine

Arrangement of basic knowledge of Java virtual machine

The tuning of the JVM is mainly for the memory area

1. The architecture of the JVM

The following figure is a simplified diagram of the memory model of the JVM:

insert image description here

There is also a local method interface in the above figure .

Among them, the stack, native method stack and program counter will not have garbage collection .

And most of the tuning of JVM is for heap memory and method area

The following is a complete JVM architecture diagram:

insert image description here

2. Detailed explanation of class loader

The following uses the Car class as an example to explain the class loader and object initialization process

insert image description here

There are the following loader types:

  • The loader that comes with the virtual machine
  • Start the class (root) loader
  • extension class loader
  • Application (system class) loader

Parental delegation mechanism :

When the class loader receives a class loading request, it will delegate the request upwards to the parent class loader for loading, and will continue to delegate upwards until the class loader is started. The startup class loader checks whether the current class can be loaded. If it can be loaded, the current class is used directly, otherwise an exception is thrown to notify other subloaders to load. until it can be loaded.

3. Sandbox Security Mechanism

(1) History of sandbox security development

The core of the Java security model is the Java sandbox (sandbox).

What is a sandbox? The sandbox is an environment that restricts the running of the program: the sandbox mechanism is to limit the Java code to the specific operating scope of the virtual machine (JVM), and strictly restrict the code's access to local system resources. Through such measures, the code is effectively guaranteed. Isolation to prevent damage to the local system.

The sandbox mainly restricts access to system resources, so what do system resources include? It mainly includes CPU, memory, file system, and network.

Different levels of sandboxes may also have different restrictions on access to these resources.

All ava programs can be run in designated sandboxes, and security policies can be customized.

In Java, the execution program is divided into two types: local code and remote code. The local code is regarded as trusted by default, while the remote code is regarded as untrusted. For trusted native code, all native resources can be accessed .
For non-trusted remote codes in early ava implementations, security relies on a sandbox (Sandbox) mechanism. The following figure shows the security model of JDK1.0:

insert image description here

But such a setting has brought obstacles to the function expansion of the program.
Therefore, in the Java1.1 version, the security mechanism has been improved, and the security policy has been added to allow users to specify the access rights of the code to local resources. The JDK1.1 security model is shown in the following figure:

insert image description here

In the Java1.2 version, the security mechanism has been improved again, and the code signature has been added. Whether it is local code or remote code, it will be loaded into the virtual machine by the class loader according to the user's security policy settings, and the operating space with different permissions , to achieve differentiated code execution permission control, as shown in the following figure is the security model of JDK1.2:

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-I4FviNHl-1663060044418) (Java virtual machine knowledge.assets/JDK1.2 sandbox.png)]insert image description here

The current latest security mechanism introduces the concept of domain , and the virtual machine loads all codes into different system domains and application domains. **The system domain part is responsible for interacting with key resources, and each application domain part accesses various required resources through some agents in the system domain. ** Different protected domains (Protected Domain) in the virtual machine correspond to different permissions (Permission). Class files that exist in different domains have all the permissions of the current domain, as shown in the latest security model (JDK1.6) as shown in the figure below.

insert image description here

(2) Basic components of the sandbox

  • Bytecode verifier (bytecode verifier) : Ensure that Java class files follow the Java language specification, which can help Java programs achieve memory protection, but not all class files will undergo bytecode verification, such as core classes.

  • Class loader (class loader) : Among them, the class loader works on the Java sandbox in 3 aspects

    • It prevents malicious code from interfering with good code
    • It guards the boundaries of trusted libraries
    • It puts the code into protection domains, which determines what the code can do.

    The virtual machine provides different namespaces for classes loaded by different class loaders. The namespace consists of a series of unique names. Each loaded class will have a name. This namespace is created by the Java virtual machine for each class. loaders, they are not even visible to each other.

    The mechanism used by the class loader is the parent delegation mechanism

    1. Loading starts from the innermost JVM's own class loader, and the outer malicious class with the same name cannot be loaded and cannot be used.
    2. Since the access domain is strictly distinguished by the package, the malicious class in the outer layer cannot gain access to the inner class through the built-in code, and the damaged code will not take effect
  • Access controller (access controller) : The access controller can control the access authority of the core API to the operating system, and the policy setting of this control can be specified by the user.

  • Security manager (security manager) : It is the main interface between the core API and the operating system, which implements permission control and has a higher priority than the access controller.

  • Security package (security package) : classes under java.security and classes under the extension package, allowing users to add new security features to their applications, including:

    • security provider
    • message digest
    • digital signature
    • encryption
    • identify

4. Native and method area and registers

(1) Native local method

Anything with the native keyword means that the scope of Java cannot be reached, and the program will call the underlying C language library.

Anyone with the native keyword will enter the local method stack and call the local method interface, that is, JNI (the local method interface is to expand the use of Java and integrate different programming languages ​​for Java.) That is: Java in the memory
area A marked area, Native Method Stack, is specially created to register the Native method, and load the method in the native method library at the time of final execution.

(2) PC register

Program Counter: Program Counter Register

Each thread has a program counter, which is private to the thread , and is a pointer to the method bytecode in the method area (used to store the address pointing to an instruction, the instruction code to be executed), which is read by the execution engine The next instruction, is a very small memory space, almost negligible.

(3) Method area

Method Area method area

The method area is shared by all threads . All fields and method bytecodes, as well as some special methods, such as constructors, interface codes are also defined here. Simply put, all defined method information is stored in this area. This area belongs to the shared area.

Static variables, constants, class information (constructors, interface definitions), and the runtime constant pool are stored in the method area, but instance variables are stored in the heap memory, which has nothing to do with the method area.

5. Stack

(1) The basic concept of the stack

That is, the stack memory, the running of the supervisor program, the life cycle and thread synchronization, the end of the thread, and the release of the stack memory. For the stack, there is no garbage collection problem. Threads are private.

The composition of the stack:

  • Eight basic types
  • object reference
  • instance method

The error that the stack is prone to is: StackOverFlowError

The following is a schematic diagram of the stack and stack frame:

insert image description here

(2) Detailed explanation of each part of the stack frame

insert image description here

  • Local variable table : The local variable table is a group of variable value storage spaces, which are used to store method parameters and local variables defined inside the method . When the Java program is compiled into a Class file, the capacity of the maximum local variable table that the method needs to allocate is determined in the max_locals data item of the Code attribute of the method table .

    When the method is executed, the virtual machine uses the local variable table to complete the transfer process of the parameter variable list .
    If it is an instance method, the Slot of each 0-bit index in the local variable table is used to pass the reference of the object instance to which the method belongs by default. In the method, this implicit parameter can be accessed through the keyword "this", and the rest of the parameters are Arranged in the order of the parameter list, occupying the local variable Slot starting from 1, after the parameter list is allocated, the remaining Slots are allocated according to the variable order and scope defined in the method body.
    The Slot in the local variable table is reusable. The scope of the variable defined in the method body does not necessarily cover the entire method. If the value of the current bytecode PC calculator has exceeded the scope of a variable, then The Slot corresponding to this variable can be used by other variables.

    If a local variable is defined but not assigned an initial value, it cannot be used.

  • Operand stack : The operand stack is also often called the operation stack, which is a last-in, first-out stack . Like the local variable table, the maximum depth of the operand stack is also written into the max_stacks data item of the Code attribute of the method table when compiling. Each element of the operand stack can be any Java data type, including long and double. The stack capacity occupied by 32-bit data types is 1, and the stack capacity occupied by 64-bit data types is 2. The unit of stack capacity is "word width". For a 32-bit virtual machine, a "word width" occupies 4 bytes. For a 64-bit virtual machine, a "word width" occupies 8 bytes.

    When a method is just executed, the operand stack of this method is empty. During the execution of the method, various bytecodes point to the operand stack to write and extract values, that is, push and pop operate.
    For example, when doing arithmetic operations, it is performed through the operand stack, or when calling other methods, parameters are passed through the operand stack.

    In the conceptual model, the two stack frames are completely independent of each other as elements of the virtual machine stack, but most virtual machine implementations will do some optimization processing to make the two stack frames partially overlap . Let part of the operand stack of the lower stack frame overlap with part of the local variable table of the upper stack frame, so that a part of the data can be shared when the method call returns without additional parameter copying and passing .

  • Dynamic link : **Each stack frame contains a reference to the method that the stack frame belongs to in the runtime constant pool. This reference is held to support the dynamic link during the method call. ** There are a large number of symbolic references in the constant pool of the Class file, and the method call instruction in the bytecode uses the symbolic reference pointing to the method in the constant pool as a parameter . Some of these symbolic references will be converted into direct references during the class loading phase or when they are used for the first time. This conversion is called static resolution. Another part will be converted into a direct reference during each runtime, this part is called a dynamic link.

  • Method return address : When a method is executed, there are two ways to exit the method.

    The first way is that the execution engine encounters a bytecode instruction returned by any method . At this time, there may be a return value passed to the upper-level method caller (the method that calls the current method is called the caller), whether there is a return value and the type of the return value will be determined according to which method return instruction is encountered. This method of exiting the method is called the normal completion exit (Normal Method Invocation Completion).

    Another way to exit is that an exception is encountered during method execution , and the exception is not handled in the method body. Whether it is an exception generated inside the Java virtual machine or an exception generated by using the throw bytecode instruction in the code, as long as If no matching exception handler is found in the exception table of this method, the method will exit. This exit method is called Abrupt Method Invocation Completion. A method that exits with an exception completion exit does not produce any return value to its caller.

    No matter what method is used to exit, before the method exits, it is necessary to return to the location where the method was called, so that the program can continue to execute. When the method returns, it may need to save some information in the stack frame to help resume the execution of its upper method state.

    Generally speaking, when the method exits normally, the value of the caller's PC counter can be used as the return address, and the counter value is likely to be saved in the stack frame.

    When the method exits abnormally, the return address is determined by the exception handler, and this part of information is generally not saved in the stack frame.

    The process of method exit is actually equivalent to popping the current stack frame, so the operations that may be performed when exiting are: restore the local variable table and operand stack of the upper method, and push the return value (if any) into the caller stack In the frame's operand stack, call the value of the PC counter to point to the instruction following the method call instruction, etc.

  • Additional information : The virtual machine specification allows specific virtual machine implementations to add some information that is not described in the specification to the stack frame, such as height-related information. This part of information depends entirely on the specific virtual machine implementation. In actual development, dynamic connection, method return address and other additional information are generally classified into one category, which is called stack frame information.

6. Heap

(1) The basic concept of heap

A JVM has only one heap memory, and the size of the heap memory can be adjusted.

After the class loader reads the class file, it generally puts the class, method, constant, variable, and real object that holds all reference types into the heap.

Heap memory can also be subdivided into the following three areas:

  • Cenozoic (Eden Park + Survival Zone) Young/New, the ratio is generally 8:1:1
  • Old age Old
  • Permanent Zone Perm

Following are the areas of JVM heap memory:
insert image description here

  • Eden Park : Eden Park is the area where objects are created, but if the Eden Park is full, GC will be called for light garbage collection. If the object is referenced at this time, it will survive and enter the Survival Zone. At this time, the memory in the Eden Park is cleared. Garbage is recycled.
  • Survival area : The memory that has not been reclaimed by mild GC will enter the survival area. There are two survival areas, one is 0 and the other is 1. The Survival Area + Eden Area is collectively called the Newborn Area . Generally speaking, the ratio of Eden to Survival Area is 8:1:1 (but it needs to be set manually)

The new generation ratio of JVM memory s0:s1:eden=1:1:8has two prerequisites:

  1. Disable memory allocation policy adaptation (enabled by default),-XX:-UseAdaptiveSizePolicy
  2. Manually set the ratio of Eden area to Survivor area,-XX:SurvivorRatio=8
  • Elderly Area : When the memory in the Survival Area is full, it will enter the Elderly Area. If the memory in the Elderly Area is full, it will trigger a heavy GC recovery, FullGC . (As long as the object that is still alive after 15 gcs will enter the old area)
  • Permanent area (metaspace) : The permanent area is resident in memory, used to store Class objects and interface metadata carried by JDK itself, and used to store the Java runtime environment. There is no garbage collection in this area, and closing the JVM virtual machine will release the memory in this area.

1. Before jdk1.6, it was called the permanent generation, and the constant pool was in the method area.
2. In jdk1.7, it was called the permanent generation, and the constant pool was in the heap. A concept was proposed that is depermanence.
3. For jdk1.8, there is no permanent generation, and the constant pool is in the metaspace.

Metaspace exists logically but not physically.

Escape analysis :

It is to analyze the dynamic scope of objects . When an object is defined in a method, it may also be referenced by external methods, such as passed to other methods as call parameters.

-XX +DoEscapeAnalysisSet escape analysis.

Using escape analysis, the compiler can do the following optimizations:

  1. Synchronization is omitted . If it is found that an object can only be accessed from one thread, then the operation of this object can be ignored.
  2. Convert heap allocation to stack allocation : if an object is allocated in a subroutine, so that a pointer to this object never escapes, the object may be a candidate for stack allocation instead of heap allocation (actually a scalar replacement)
  3. Separation of objects or scalar replacement : Some objects may not need to exist as a continuous memory structure and can be accessed, then part (or all) of the object may not be stored in memory, but stored in CPU registers.

When dynamically compiling a synchronization block, the JIT compiler can use escape analysis to determine whether the lock object used by the synchronization block can only be accessed by one thread and not released to other threads. If the lock object used by the synchronization block is analyzed and confirmed to be accessed by only one thread, it will be optimized for lock elimination .

(2) Operating heap memory

  • Use RunTimethe class to get the maximum memory used by the virtual machine and the total memory of the JVM
  //返回虚拟机试图使用的最大内存
        long maxMemory = Runtime.getRuntime().maxMemory();
        //返回JVM的总内存
        long totalMemory = Runtime.getRuntime().totalMemory();

        System.out.println("maxMemory:"+maxMemory+"字节\t,"+maxMemory/(double)1024/1024+"MB");
        System.out.println("totalMemory:"+totalMemory+"字节\t,"+totalMemory/(double)1024/1024+"MB");

The result is:

maxMemory:1821376512字节	,1737.0MB
totalMemory:124780544字节	,119.0MB

It can be seen that the maximum memory of maxMemory is about a quarter of the total memory, and the total memory of the JVM is 119MB

  • We can change the corresponding maximum memory and total memory by modifying the corresponding parameters

-Xms1024m -Xmx1024m -XX:+PrintGCDetails

The former represents the memory allocated during initialization (1/64 of the default memory), and the latter represents the maximum memory allowed to be allocated (1/4 of the default memory)

What should I do if I get OOM (Out of Memory Error)?

  1. Try to expand the heap memory and see the result
  2. Analyze memory to see where problems occur

(3) JVM common parameter options

parameter options meaning
-Xms The initial heap size. Such as: -Xms256m
-Xmx Maximum heap size. Such as: -Xmx512m
-Xmn Cenozoic size. Usually 1/3 or 1/4 of Xmx. New generation = Eden + 2 Survivor spaces. The actual available space is = Eden + 1 Survivor, which is 90%
-Xss JDK1.5+ each thread stack size is 1M, generally speaking, if the stack is not very deep, 1M is definitely enough.
-XX: NewRatio The ratio of the new generation to the old generation, such as –XX:NewRatio=2, the new generation occupies 1/3 of the entire heap space, and the old generation occupies 2/3
-XX:SurvivorRatio The ratio of Eden to Survivor in the new generation. The default value is 8. That is, Eden occupies 8/10 of the new generation space, and the other two Survivors each occupy 1/10
-XX:PermSize The initial size of the permanent generation (method area)
-XX:MaxPermSize The maximum value of the permanent generation (method area)
-XX:+PrintGCDetails GC information
-XX:+HeapDumpOnOutOfMemoryError Let the virtual machine dump the current memory heap dump snapshot when memory overflow occurs, so as to analyze
-XX:MaxTenuringThreshold=xxx Through this parameter, you can set the time to enter the old age

(4) Jprofiler memory snapshot analysis tool

  1. effect:
  • Analyze Dump memory files to quickly locate memory leaks
  • get the data in the heap
  • get large object
  1. Download and install

Search for JProfiler in the plug-in market of idea, and install it.

After the installation is complete, it will display:

insert image description here

At the same time, download version 12 from the official website of JProfiler, and use the following registration code to register and install.

L-J12-STALKER#5846458-y8bdm6q8gtr7b#228a

L-J12-STALKER#8338547-qywh5933xu2r3#a4a4

Just start it in the terminal:

cd /opt/jprofiler12/bin
jprofiler
......
# 启动成功

Complete integration with idea
insert image description here

  1. Use positioning error

Set the following parameters on the corresponding class

-Xms1m-Xmx8m -XX:+HeapDumpOnxxxError

When an error occurs, the JProfiler plug-in can automatically generate the corresponding pro file, which can be opened in JProfiler to complete the analysis.

7. GC: garbage collection

(1) The basic concept of GC

The scope of GC is essentially only heap and method area

When the JVM performs GC garbage collection, it does not recycle the Eden area, the survivor area (from, to) and the old area at one time. Most of the recycling is in the Eden area .

GC classification:

  • Light GC (ordinary GC, Minor GC): At this time, if the new object cannot be created in the Eden area (the Eden area cannot be accommodated), a Young GC will be triggered. At this time, the objects in the S0 area (surviving area 0) and the Eden area will be Carry out reachability analysis together, find out the active object, copy it to the S1 area and clear the objects in the S0 area and Eden area, so that those unreachable objects are cleared, and the S0 area and the S1 area are exchanged.
  • Heavy GC (global GC, Major GC): GC that occurs in the old age, basically a Minor GC occurs once a Major GC occurs. And the speed of Major GC is often 10 times slower than Minor GC.

(2) GC common algorithm

1. Reference counting

The reference counting algorithm is a counter for each object to save the number of times the object is referenced. If the object is referenced by other objects, the counter is incremented by 1, and the counter is decremented by 1 when the reference to the object ends. When the counter is 0, the object is considered to have been If there is no reference, it will be recycled.

However, the reference counting method will have a circular dependency problem . If there are two instance objects that refer to each other, the counter will always be 1, and the GC will never be able to recycle them.

Reference counting diagram:

String str=new String("gc");
str=null;

insert image description here

2. Replication Algorithm

The new generation mainly uses the replication algorithm

Divide the living memory space into two blocks, and only use one of them at a time. During garbage collection, copy the surviving objects in the memory being used to the unused memory block, and then clear all the objects in the memory block being used. object, swap the roles of the two memory (that is, survive from area to survive to area, and the to area is always guaranteed to be empty), and finally complete garbage collection.

Copy the reachable object directly to another area. After the copy is completed, area A is useless, and the objects in it can be cleared directly, and the copy algorithm is used in the new generation.

There are only two ways to judge surviving objects: reference counting and reachability analysis
insert image description here

It should be noted that if an object in the new generation has not been cleared after 15 gcs, it will enter the old generation.

However, you can set the value of entering the old age by setting parameters. -XX:MaxTenuringThresholdIf it is set to 0, it means that the young generation objects will directly enter the old age area without passing through the survivor area. This increases the survival time of the object in the young generation and increases the probability of being recycled in the young generation.

Pros: no memory fragmentation

Disadvantages: The memory space is wasted, half of the space is always empty, and it is only applicable when the object survival is low.

3. Mark Sweep Algorithm

The whole process of Mark-Sweep algorithm is divided into two steps just like its name: mark (Mark) and clear (Sweep).

  • Marking process: The marking process is actually to determine whether the object is a recyclable object. In Java, the most commonly used is: **root reachability analysis algorithm. **As shown below:

insert image description here

You can mark any kind of object. If it is marked recyclable, then clean up the recyclable object, and mark the non-recyclable object, and also clean up the recyclable object.

  • Clearing process: Just release the heap space occupied by recyclable objects directly.

shortcoming:

  • Space problem: Since the physical memory allocated in the heap memory between objects is not continuous, after a mark and clear, there is a high probability that memory fragmentation will occur
  • Time problem: Since it is divided into two processes (marking and clearing), when there are many recyclable objects in the heap, the algorithm needs to perform a lot of marking and clearing . Here is a problem. With the increase of recyclable objects, mark And the efficiency of clearing will decrease; moreover, due to the discontinuity of space, the free list must be traversed every time it is allocated again.
  • In the marking and cleaning phases, the entire heap must be traversed, and SWT (Stop The World) takes a long time.

Advantages: No additional space is required, which makes up for the defects of the copy algorithm.

4. Tag compression algorithm

That is, re-optimize (optimize memory fragmentation) based on the mark-clear algorithm

Scan again after the mark-and-sweep algorithm, moving surviving objects toward one end.

But there is an extra cost of moving surviving objects.

Summarize:

  • Memory Efficiency (Time Complexity): Replication Algorithm > Mark Sweep Algorithm > Mark Compression Algorithm
  • Memory uniformity: copy algorithm = mark compression algorithm > mark removal algorithm
  • Memory Utilization: Mark Compression Algorithm = Mark Clear Algorithm > Copy Algorithm

(3) Summary of Garbage Collection

  • Judgment of garbage objects : reference counter, reachability analysis (virtual machine stack-local variables, objects referenced by method area class attributes and constants, and local method stacks can all be used as GCroot)
  • Recycling strategies : mark clearing (poor efficiency, memory fragmentation), copying (no fragmentation, but wasting time), mark finishing (no fragmentation, but objects need to be moved)

Eight, JMM (Java Memory Model)

(I. Overview

JMM is the Java Memory Model, [JMM] (abbreviation for Java Memory Model) allows the compiler and the cache to have important privileges in the order in which data moves between processor-specific caches (or registers) and main memory, unless the programmer uses A volatile or synchronized explicitly requests certain visibility guarantees.

The Java Memory Model (JMM) is defined in the Java Virtual Machine Specification, which is used to shield the memory access differences of various hardware and operating systems, so that Java programs can achieve consistent concurrency effects on various platforms. , JMM specifies how the Java virtual machine and computer memory work together: specifies how and when a thread can see the value of shared variables modified by other threads, and how to synchronize access to shared variables when necessary.

**The memory defined by the JMM model is divided into working memory and main memory. **Working memory is a copy copied from the main memory, which is private to the thread. When the thread starts, copy the copy from the main memory to the working memory, execute the relevant instruction operation, and finally write it back to the main memory.

As shown below:

insert image description here

(2) Features

The three major characteristics of JMM are also places where problems often occur for concurrent threads. Therefore, JMM can also be said to be mainly a summary of the methods and ideas for solving these three core problems.

1. Atomicity

Atomicity means that an operation is uninterruptible. Even in a multi-threaded environment, once an operation starts, it will not be affected by other threads. For example, two threads operate on the same shared variable, no matter how the threads run, the value of the shared variable is unique, that is to say, the threads do not interfere with each other . The root cause of multi-threaded security problems is that non-atomic operations are performed on the same shared resource.

have to be aware of is:

For 32-bit systems, reading and writing long and double data (64-bit data) is not atomic, but reading and writing other basic data types is atomic. Reading and writing of long and double types is not atomic because of the length of the machine word. Each atomic read and write is 32 bits. This will cause one thread to read the first 32 bits of data, and it will be another thread’s turn. Reading just reads the last 32 bits of the variable, which causes non-atomicity.

In addition, when the computer executes the program, it will perform a series of optimization operations, namely: instruction rearrangement

In order to improve performance, there are generally 3 ways to rearrange

insert image description here

  • Compiler optimization rearrangement : the compiler rearranges the execution order of statements without changing the thread semantics
  • Instruction parallel rearrangement : Since modern processors use instruction-level parallel technology to overlap and execute multiple instructions, the processor can change the statement corresponding to the The order in which machine instructions are executed.
  • Memory system rearrangement : Since modern processors use a multi-cache architecture design, there is a time difference in data synchronization between the memory and the cache, which makes loads and stores seem to be executed out of order.

The above rearrangement is for performance optimization, but it will cause visibility problems in a multi-threaded environment.

2. Visibility

**Visibility refers to whether other threads can immediately know the modified value when a thread modifies the value of a shared variable. **There is no visibility problem for serial programs (similar to concatenation), only when concurrent programs share certain resources.

Because in a multi-threaded environment, all threads copy a part of the main memory to their own private working memory for operation, and then write directly to the main memory. At this time, it is easy to appear the working memory and the main memory. Synchronization problem. And instruction rearrangement may also affect visibility, because they will change the order of program instruction execution.

3. Orderliness

The so-called orderliness means that under a single thread, the execution of the code is executed in order, but in multi-threading, it cannot always be executed in order, and there will be out-of-order phenomena.

(3) Solutions

1. Language-level solutions

  • For security issues caused by atomicity:

You can use the atomic type data provided by the JVM, or you can use the Synchronized keyword or the method of the Lock interface to ensure atomicity.

  • For thread working memory and main memory visibility issues:

You can use locks or use the Volatile keyword to make variables modified by one thread visible to other threads.

In addition to guaranteeing visibility, Volatile can also prevent instruction rearrangement (the underlying prohibition of instruction rearrangement is achieved by setting a memory barrier), but it does not guarantee atomicity.

2. JMM internal solution

(1)as-if-serial

Regardless of how to reorder, the execution result of a single thread is immutable. Compilers, processors, etc. must follow the as-if-serial semantics, that is, do not reorder those with data dependencies, and reorder those without data dependencies. Sort. This is a protection mechanism for single-threaded programs.

(2)happens-before

Primarily used to illustrate memory visibility between operations.

  • If one operation happens-berfore another operation, then the results of the first operation will be visible to the second operation, and the execution order of the first operation will be before the second operation.
  • If there is a happens-before relationship between the two operations, it does not have to be executed in the order established by the happens-before principle. If the execution result after reordering is consistent with the result of executing according to the happens-before relationship, then the reordering Not illegal.

Eight rules need to be followed: (Excerpt from "In-depth Understanding of Java Virtual Machine")

  • Program order rule: In a thread, according to the code order, the operation written in the front happens before the operation written in the back.
  • Monitor lock rule: An unLock operation occurs first before a lock operation on the same lock occurs later
  • Volatile variable rule: the write operation to a variable happens before the read operation on the variable;
  • Thread start rule: the start() method of the Thread object occurs first in every action of this thread;
  • Thread termination rules: All operations in the thread occur before the termination detection of the thread. We can detect that the thread has terminated execution by means of the Thread.join() method ending and the return value of Thread.isAlive();
  • Thread interruption rules: the call to the thread interrupt() method occurs first when the code of the interrupted thread detects the occurrence of an interrupt event;
  • Object finalization rules: the initialization of an object occurs before the start of its finalize() method;
  • Transitivity: If operation A happens before operation B, and operation B happens before operation C, it can be concluded that operation A happens before operation C;

insert image description here

Guess you like

Origin blog.csdn.net/qq_50824019/article/details/126837273