当前位置:网站首页>The core concept of JMM: happens before principle
The core concept of JMM: happens before principle
2022-06-24 22:40:00 【Java enthusiast】
JMM Designers' problems and perfect solutions
in fact , from JMM From the designer's point of view , Visibility and order are actually two contradictory points :
- One side , For programmers , We want the memory model to be easy to understand 、 Easy to program , So JMM Designers should provide programmers with a strong enough memory visibility guarantee , In technical terms, it's called “ Strong memory model ”.
- And on the other hand , Compilers and processors want the memory model to constrain them as little as possible , So they can do as many optimizations as possible ( Like reordering ) To improve performance , therefore JMM Designers of the compiler and processor restrictions to be relaxed as much as possible , In technical terms, it's called “ Weak memory model ”.
For this question , from JDK 5 Start , That is to say JSR-133 In memory model , Finally, a perfect solution is given , That's it Happens-before principle ,Happens-before Literal translation “ Happen first ”,《JSR-133:Java Memory Model and Thread Specification》 Yes Happens-before The definition of a relationship is as follows :
1) If an 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 before the second operation .
2) There is... Between the two operations Happens-before Relationship , It doesn't mean that Java The specific implementation of the platform must be in accordance with Happens-before The relationship is executed in the order specified . If the execution result after reordering , And press Happens-before The result of the relationship is the same , So this sort of reordering is not illegal ( in other words ,JMM Allow this reorder )
It's not hard to understand , The first 1 The first definition is JMM Commitment to programmer's strong memory model . From a programmer's point of view , It can be understood in this way Happens-before Relationship : If A Happens-before B, that JMM The programmer will be assured that — A The result of the operation will be B so , And A The order of execution is B Before . Be careful , This is just Java The memory model guarantees the programmer !
It should be noted that , differ as-if-serial Semantics can only work on a single thread , The two operations mentioned here A and B It can be within a thread , It can also be between different threads . in other words ,Happens-before Provide Cross thread memory visibility guarantee .
For this second 1 Definitions , Let me give you an example :
// The following operations are in thread A In the implementation of
i = 1; // a
// The following operations are in thread B In the implementation of
j = i; // b
// The following operations are in thread C In the implementation of
i = 2; // c
Assuming that thread A The operation a Happens-before Threads B The operation of b, Then we can confirm the operation b After execution , Variable j The value of must be equal to 1.
There are two reasons for this conclusion : One is based on Happens-before principle ,a The result of the operation is right b so , namely “i=1” The results can be observed ; The two is thread. C It's not running yet , Threads A No other thread will change the variables after the operation i Value .
Now consider threads C, We still keep a Happens-before b , and c Appear in the a and b Between operations , however c And b No, Happens-before Relationship , in other words b It's not necessarily possible to see c The result of the operation . that b The result of the operation is j I'm not sure , May be 1 It could be 2, This code is thread unsafe .
Look again. Happens-before Of the 2 Definitions , This is a JMM Guarantees for compiler and processor weak memory models , Given sufficient operational space , There are certain constraints on the reordering of compilers and processors . in other words ,JMM It's actually following a basic principle : As long as the execution result of the program is not changed ( It refers to single thread program and correctly synchronized multithreaded program ), Compiler and processor can be optimized .
JMM And the reason for that is : Programmers don't care if these two operations are really reordered , The programmer's concern is that the execution result cannot be changed .
Words may not be easy to understand , Let's take an example , To explain the next 2 Definitions : Although there is a gap between the two operations Happens-before Relationship , But it doesn't mean Java The specific implementation of the platform must be in accordance with Happens-before The relationship is executed in the order specified .
int a = 1; // A
int b = 2; // B
int c = a + b; // C
according to Happens-before The rules ( I'll talk about ), The above code exists 3 individual Happens-before Relationship :
- A Happens-before B
- B Happens-before C
- A Happens-before C
You can see it , stay 3 individual Happens-before In relationship , The first 2 And the first 3 One is necessary , But the first 1 One is unnecessary .
in other words , although A Happens-before B, however A and B Reordering between will not change the execution result of the program at all , therefore JMM It allows the compiler and processor to perform this reordering .
Look at this one JMM It's more intuitive :
Actually , It can be understood so simply , for fear of Java Programmers to understand JMM The memory visibility guarantees the learning of complex reordering rules and the specific implementation methods of these rules ,JMM There is such a simple and easy to understand Happens-before principle , One Happens-before Rules correspond to reordering rules for one or more compilers and processors , such , We just need to figure out Happens-before That's it .
8 strip Happens-before The rules
《JSR-133:Java Memory Model and Thread Specification》 It is defined as follows Happens-before The rules , These are the JMM in “ natural ” Happens-before Relationship , these Happens-before Relationships exist without any synchronizer assistance , Can be used directly in coding . If the relationship between two operations is not in this column , And can't be derived from the following rules , Then they have no sequential guarantee ,JVM You can reorder them at will :
1) Program Order Rule (Program Order Rule): In a thread , In the order of control flow , Writing takes place first (Happens-before) The operation of writing at the back . Be careful , This is about the sequence of control flow, not the sequence of program code , Because we need to think about branches 、 Circulation and other structures .
It's easy to understand , In line with our logical thinking . For example, the example we mentioned above :
int a = 1; // A
int b = 2; // B
int c = a + b; // C
According to the order of procedure , The above code exists 3 individual Happens-before Relationship :
- A Happens-before B
- B Happens-before C
- A Happens-before C
2) Tube lock rule (Monitor Lock Rule): One unlock The operation occurs first of all on the same lock lock operation . It must be emphasized here that “ Same lock ”, and “ Back ” It refers to the order of time .
This rule is aimed at synchronized Of .JVM Not yet lock and unlock Operation is directly open to users , But it provides a higher level of bytecode instructions monitorenter and monitorexit To implicitly use these two operations . These two bytecode instructions reflect Java In the code is the synchronization block — synchronized.
for instance :
synchronized (this) { // Lock automatically here
if (x < 1) {
x = 1;
}
} // It will unlock automatically here
According to the tube side locking rules , hypothesis x The initial value of 10, Threads A After executing the code block x The value of will become 1, Automatic release lock after execution , Threads B When entering a code block , Able to see threads A Yes x Write operations for , So threads B Be able to see x == 1.
3)volatile Variable rule (Volatile Variable Rule): To a volatile The write operation of the variable first occurs after the read operation of the variable , there “ Back ” It also refers to the order of time .
The rule is JDK 1.5 Version pair volatile Semantic enhancement , It's of great significance , It's easy to get visibility done with this rule .
for instance :
Assuming that thread A perform writer() After method , Threads B perform reader() Method .
According to the order of procedure :1 Happens-before 2;3 Happens-before 4.
according to volatile Variable rule :2 Happens-before 3.
According to the transitivity rules :1 Happens-before 3;1 Happens-before 4.
in other words , If the thread B I read “flag==true” perhaps “int i = a” So thread A Set it to “a=42” For threads B Is visible .
Look at the picture below :
4) Thread start rule (Thread Start Rule):Thread Object's start() Method occurs first in every action of this thread .
For example, the main thread A Start the child thread B after , Sub thread B You can see that the main thread is starting the sub thread B All operations before .
5) Thread termination rule (Thread Termination Rule): All operations in a thread occur first at the termination detection of this thread , We can go through Thread Object's join() Whether the method ends 、Thread Object's isAlive() Check whether the thread has terminated the execution .
6) Thread interrupt rule (Thread Interruption Rule): For threads interrupt() Method calls occur first when the interrupted thread's code detects the occurrence of an interrupt event , Can pass Thread Object's interrupted() Method detects if an interrupt has occurred .
7) Object termination rule (Finalizer Rule): Initialization of an object completed ( End of constructor execution ) What happened first finalize() The beginning of the method .
8) Transitivity (Transitivity): If you operate A First occurs in operation B, operation B First occurs in operation C, Then we can get the operation A First occurs in operation C Conclusion .
“ First in time ” And “ Happen first ”
Above 8 In two rules , Also mentioned time successively , that ,“ First in time ” And “ Happen first (Happens-before)” What's the difference ?
One operation “ First in time ” Does it mean that this operation will be “ Happen first ” Well ? One operation “ Happen first ” Can we deduce that this operation must be “ First in time ” Well ?
unfortunately , Neither of these inferences holds true .
Give two examples to demonstrate :
private int value = 0;
// Threads A call
pubilc void setValue(int value){
this.value = value;
}
// Threads B call
public int getValue(){
return value;
}
Suppose there are threads A and B, Threads A First ( The order of time ) Called setValue(1), Then the thread B Calling... Of the same object getValue() , So thread B What is the return value received ?
According to the above Happens-before Of 8 The big rules are analyzed in turn :
Because the two methods are separated by threads A and B call , Not in the same thread , So the procedural order rule doesn't apply here ;
Because there is no synchronized Synchronized block , It doesn't happen naturally lock and unlock operation , So the tube lock rule doesn't apply here ;
alike ,volatile Variable rule , Thread start 、 End 、 Interruption rules and object termination rules have nothing to do with this .
Because there's no one that works Happens-before The rules , So the first 8 There is no way to talk about the transitivity of these rules .
So we can judge , Although thread A In terms of operation time, it is prior to thread B Of , But it can't be said that A Happens-before B, That is to say A The result of thread operation B Not necessarily visible . therefore , This code is thread unsafe .
It's easy to fix this problem ? Since I'm not satisfied Happens-before principle , Then I'll modify it to make it satisfied . Let's say a Getter/Setter All methods are used synchronized modification , In this way, the pipe locking rules can be applied ; Take... For example value Defined as volatile Variable , In this way, you can apply volatile Variable rules, etc .
This example , It is argued that One operation “ First in time ” Doesn't mean this operation will be “ Happen first (Happens-before)”.
Let's take another example :
// The following operations are performed in the same thread
int i = 1;
int j = 2;
Suppose that the two assignment statements in this code are in the same thread , So according to the order of procedure ,“int i = 1” The operation of the first occurrence (Happens-before) On “int j = 2”, however , Remember Happens-before Of the 2 Is there a definition ? I still remember that JMM In fact, it is to abide by such a principle : As long as the execution result of the program is not changed ( It refers to single thread program and correctly synchronized multithreaded program ), Compiler and processor can be optimized .
therefore ,“int j=2” This code is likely to be executed by the processor first , Because it doesn't affect the final result of the program .
that , This example , It is argued that One operation “ Happen first (Happens-before)” It doesn't mean that this operation must be “ First in time ”.
such , To sum up, there are two cases , We can come to the conclusion that :Happens-before There is basically no causal relationship between principle and time sequence , So when we measure concurrency security , Try not to be disturbed by the time sequence , Everything must be done with Happens-before The principle shall prevail .
Happens-before And as-if-serial
Sum up , I think I can understand the following sentence Happens-before 了 , This sentence has appeared several times before :JMM It's actually following a basic principle , That is, as long as the execution result of the program is not changed ( It refers to single thread program and correctly synchronized multithreaded program ), Compiler and processor can be optimized .
Look back as-if-serial semantics : No matter how reorder , The result of program execution cannot be changed in single thread environment .
Did you find that ? In essence Happens-before Relationship and as-if-serial Semantics is one thing , It's all for the sake of not changing the result of program execution , Improve the parallelism of program execution as much as possible . But the latter only works on a single thread , The former can work in a multi-threaded environment with correct synchronization :
- as-if-serial Semantics ensure that the execution result of a program in a single thread is not changed ,Happens-before The relationship ensures that the execution result of a multithreaded program that is correctly synchronized is not changed .
- as-if-serial Semantics create an illusion for programmers who write single threaded programs : Single threaded programs are executed in the order of programs .Happens-before Relationships create an illusion for programmers who write multithreaded programs that are properly synchronized : The correct synchronization of multithreaded programs is by pressing Happens-before In a specified order .
边栏推荐
- NiO zero copy
- Publicity of the second batch of shortlisted enterprises! Annual Top100 smart network supplier selection
- ThreadLocal内存泄漏问题
- Web攻击之CSRF和SSRF
- NIO、BIO、AIO
- Use of selector for NiO multiplexing
- Servlet details
- Introduction, installation and use of postman tool
- Envoy obtain the real IP address of the client
- Docker 安装 Redis-5.0.12,详细步骤
猜你喜欢
FANUC机器人_KAREL编程入门学习(1)
[personal experiment report]
详细了解关于sentinel的实际应用
Future development of education industry of e-commerce Express
理想L9,智能座舱新潮流
Unable to use the bean introduced into the jar package
A girl has been making hardware for ten years. 。。
Introduction, installation and use of postman tool
The usage difference between isempty and isblank is so different that so many people can't answer it
Online filing process
随机推荐
Relationnet++: a representation of fusion of multiple detection targets based on transformer | neurips 2020
如何提取网页中的日期?
In the multi network card environment, the service IP registered by Nacos is incorrect, resulting in inaccessible services
Ansible basic configuration
面试害怕被问MySQL相关问题 ?这份三万字精华总结 + 面试100 问,吊打面试官完全够了
Heartless sword Chinese English bilingual poem 003 The sea of books
软件设计的七大原则
Online filing process
短视频商城系统,scroll-view如何自适应页面剩余高度
Uncover the secret of station B. is it true that programmers wear women's clothes and knock code more efficiently?
Process communication mode
进程的通信方式
Docker 安装 MySQL 8.0,详细步骤
Learning notes 23-- basic theory of multi-sensor information fusion (Part I)
Can AI chat robots replace manual customer service?
CDN principle
Seven principles of software design
Common voting governance in Dao
详细了解Redis的八种数据类型及应用场景分析
socket done