Visibility of multithreading
The modification of shared variable value by one thread can be seen by other threads in time.
If a variable has copies in the working memory of multiple threads, then this variable is the shared variable of these threads.
Java Memory Model
JMM (JAVA memory model, referred to as JMM) describes the access rules of various variables (thread shared variables) in Java programs, as well as the underlying details of storing variables in memory and reading variables out of memory in the JVM. It follows four principles:
- All variables are stored in main memory
- Each thread has its own independent working memory, which holds a copy of the variables used by the thread (a copy of the variables in the main memory)
- All operations of a thread on a shared variable must be performed in its own working memory and cannot be read or written directly from the main memory
- Variables in working memory of other threads cannot be accessed directly between different threads, and the transfer of variables between threads needs to be completed through main memory
The principle of shared variable visibility
To be seen in time by thread 2, the modification of shared variables by thread 1 must go through the following two steps:
- Refresh the updated shared variables in working memory 1 to main memory
- Update the value of the latest shared variable in main memory to working memory 2
Java’s memory model:
There are two ways to implement visibility supported at the Java language level:
JMM regulations on synchronized:
- Before thread unlocking, the latest value of shared variable must be refreshed to main memory
- When a thread is locked, the value of the shared variable stored in the working memory is cleared, so that when using the shared variable, the latest value must be re read from the main memory. (Note: unlocking and locking refer to the same lock)
Therefore, the thread executes synchronized code to execute the process of mutex:
- Get mutex.
- Clear working memory.
- Copy the latest copy of variables from main memory to working memory.
- Execution code
- Refresh the value of the changed shared variable to main memory
- Release mutex
After JDK6, synchronize is not just a mutex.
Atomicity is not guaranteed, but volatile is suitable for modifying state tagging
It is realized by adding memory barrier and forbidding reordering optimization
- Insert the storestore barrier before each volatile write and the storeload barrier after each write
- Insert the loadload barrier before each volatile read operation and the loadstore barrier after each read operation
Generally speaking, when a volatile variable is accessed by a thread, it is forced to reread the value of the variable from main memory, and when the variable changes, it is forced to refresh the latest value to main memory. In this way, different threads can always see the latest value of the variable at any time.
Volatile write operation:
Volatile read operation:
The order of multithreading
In JAVA memory model, compiler and processor are allowed to reorder instructions, but the reordering process will not affect the execution of single threaded programs, but will affect the correctness of multithreaded concurrent execution.
Instruction reordering: the order of code writing is different from that of actual execution. Instruction reordering is an optimization made by compiler or processor to improve program performance.
- Compiler optimized reordering (compiler optimized)
- Instruction set parallel reordering (processor optimization)
- Reordering of memory systems (processor optimization)
Happens before principle
JMM can provide cross thread memory visibility guarantee to programmers through the happens before relationship (if there is a happens before relationship between a thread’s write operation a and B thread’s read operation B, although a operation and B operation are executed in different threads, JMM guarantees to programmers that a operation will be visible to B operation).
- Program order rule: the execution result of a piece of code in a thread is orderly. It will also rearrange the instructions, but whatever it is, the result will not change according to the order of our code!
- Management lock rule: no matter in single thread or multithreaded environment, for the same lock, after one thread unlocks the lock, another thread can see the operation result of the previous thread after acquiring the lock! (tube is a general synchronization primitive, synchronized is the realization of tube.)
- Volatile variable rule: if a thread writes a volatile variable first, and then a thread reads the variable, the result of the write operation must be visible to the read thread.
- Transmission rules: the principles of happens before are transitive, i.e. a happens before B, B happens before C, then a happens before C.
- Thread start rule: during the execution of main thread a, start sub thread B, then the modification result of shared variable by thread a before starting sub thread B is visible to thread B.
- Thread termination rule: during the execution of main thread a, sub thread B is terminated, so the modification result of shared variable by thread B before termination can be seen in thread a.
- Thread interrupt rule: the call to the thread interrupt() method first occurs when the interrupted thread code detects the occurrence of the interrupt event. You can detect whether the interrupt occurs through thread. Interrupted().
- Object termination rule: the completion of the initialization of an object, that is to say, the end of the execution of the constructor must be happens before its finalize () method.
The above is the whole content of this article. I hope it will help you in your study, and I hope you can support developepaer more.