当前位置:网站首页>JMM memory model and volatile implementation principle
JMM memory model and volatile implementation principle
2022-07-16 09:12:00 【huisheng_ qaq】
jmm Underlying implementation
One , In depth understanding of java Memory model
1, What is? jmm Model
java memory model,java Memory model , It is an abstract specification for multithreading , It is mainly aimed at the concurrent state of multithreading , How shared resources are accessed .jmm It's just an abstract concept , It doesn't really exist .
jvm The running entity is thread , Each thread is creating jvm Will create a working memory , For storing private data .java The memory model stipulates that all shared variables are stored in main memory , Main memory is a shared memory area , Private threads can access . But thread operation variables must be carried out in working memory , That is, by copying , Write the thread back to the main thread after the operation on the thread is completed . Cannot directly manipulate variables in main memory , It must be copied to the working memory through a copy of the variable . Of course jmm This main memory is not like jvm There are also real specific areas , It's just a model drawn from an image , That is, after the thread is started , There will be such invisible norms .
Working memory is private data , Therefore, different threads cannot access each other's working memory , That is, local variables are invisible to other threads , The communication between threads needs to be completed through the main thread
As shown in the figure below .
Shared variables are stored in main memory , Threads ABC By copying this variable, it is added to the working memory of the current thread as a copy . Main memory mainly stores java Instance object of . All created instance objects are stored in main memory . Because it is a shared area , Thread safety problems may occur when multiple threads access the same variable . Like the one below initFlag This is stored in main memory , Threads AB Just two independent threads , Will access this variable in the main memory initFlag
public class Jmm_Study {
// Shared variables , Stored in main memory
private volatile static boolean initFlag = false;
// Counter
private volatile static int counter = 0;
public static void refresh(){
log.info("refresh data.......");
initFlag = true;
log.info("refresh data success.......");
}
public static void main(String[] args){
Thread threadA = new Thread(()->{
while (!initFlag){
//System.out.println("runing");
//counter++;
}
log.info(" Threads :" + Thread.currentThread().getName()
+ " The current thread sniffs initFlag A change of state ");
},"threadA");
threadA.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread threadB = new Thread(()->{
refresh();
},"threadB");
threadB.start();
}
}
2, Eight atomic operations of data synchronization
1,lock: A variable acting on main memory , Mark a variable as a thread exclusive state
2,unlock: Release a variable that is locked , Freed variables can be locked by other threads
3,read( Read ): Act on main memory , You need to copy the variable first , Then transfer the variable value to the working memory
4,load( load ): In working memory , You need to get the transferred copy variables , And stored in the working memory
5,use( Use ): You need to pass the obtained variables to the execution engine
6,assign( assignment ): The execution engine will assign the received variable to the variable of working memory
7,store( Storage ): After modifying the transmitted copy , The modified value will be stored and sent to main memory
8,write( write in ): The stored variable will be written back to main memory
That is, every operation is atomic , That is, it cannot be interrupted during operation . And you must press read–>load–>use 、assign–>store–>write In this order , Disorder is not allowed
3,java Three features of concurrency
visibility : be based on jmm The memory model of , Internal variables between threads are not accessible . So in order to know that other threads have modified the variables of this object , Your own thread should also know , Therefore, this visibility specification is added . Threads B Changed the variable value of main memory , You need to notify the thread A, This value has been modified , And get the new value again . Such as through volatile Realization
Atomicity : Or at the same time , Or fail at the same time . An operation is not interruptible , Even in a multithreaded environment , Once an operation is started, it will not be affected by other threads .
Orderliness : From the perspective of time slice , The code should be executed from top to bottom , Such as entering and leaving the stack . But the compiler thinks that if you experience instruction rearrangement , That is, the execution order of the code is inconsistent with the writing order of the code , In this case cpu Will be more efficient . except cpu outside , This java The compiler of will also rearrange the instructions of this code .
volatile:java A lightweight lock in concurrency . Can guarantee visibility , It can also ensure order , But there's no guarantee of atomicity
4,volatile
In bytecode : The object will have a ACC_VOLATILE Instructions
At the bottom : Mainly through this EMSI agreement , To ensure the consistency of this cache .
In terms of phenomena : It can mainly ensure the visibility and order of data
It can ensure that other threads can see it in time after modification . This is mainly achieved by caching rows . But without volatile You can also see the changes of other threads , But the time of seeing is uncertain .volatile It just ensures the timeliness .
You can find , Not in use synchronized When locked , This volatile Embellished counter This atomicity is not guaranteed .
private volatile static int counter = 0;
static Object object = new Object();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(()->{
for (int j = 0; j < 10000; j++) {
// Guaranteed atomicity
//synchronized (object){
//counter++;// three - read , Self adding , Write back to
//}
counter++;
}
});
thread.start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter);
}
Suppose two threads A and B Operate this count++, Through the operation of these eight atomic classes, we can find , You need to add the data to the working memory first , After the final modification, the data is returned to the main memory , Therefore, each thread has the following two steps in the working memory :
counter = 0; Threads A1 counter = 0; Threads B1 ...
counter = counter + 1; Threads A2 counter = counter + 1; Threads B2 ...
Because in the multithreaded scenario , Each thread gets cpu All resources are polled . Therefore, the following scenarios may occur , Threads A In carrying out the A1 when ,cpu The resource is now given to the thread B, Threads B Will go to the main memory to get this counter And modify this counter value , After completion, the value will be returned to main memory , And then it will tell other threads that this value has been modified , The thread A Received this notice , Therefore, you will also get this value from the main memory , however , Pre existing threads A Of A2 Steps will be discarded , This will lead to counter Add less 1, This explains why the final result is smaller than the above 100000 了 . therefore volatile Atomicity between threads is not guaranteed .
Internal order is achieved through memory barrier , Command rearrangement is prohibited . The memory barrier will tell the compiler , Where this instruction rearrangement cannot be implemented , Otherwise, an error will be reported directly .
public class CodeReorder {
private static int x = 0, y = 0;
private static int a = 0, b = 0;
public static void main(String[] args) throws InterruptedException {
int i = 0;
for (;;){
i++;
x = 0; y = 0;
a = 0; b = 0;
Thread t1 = new Thread(new Runnable() {
public void run() {
shortWait(10000);
a = 1;
x = b;
// Manual instruction rearrangement
UnsafeInstance.reflectGetUnsafe().fullFence();
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
b = 1;
UnsafeInstance.reflectGetUnsafe().fullFence();
y = a;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
String result = " The first " + i + " Time (" + x + "," + y + ")";
if(x == 0 && y == 0) {
System.out.println(result);
break;
} else {
log.info(result);
}
}
}
/** * Wait for a while , The unit of time is nanosecond * @param interval */
public static void shortWait(long interval){
long start = System.nanoTime();
long end;
do{
end = System.nanoTime();
}while(start + interval >= end);
}
}
5,CPU Cache consistency
5.1MESI agreement
MESI Provisions of the agreement : A read operation on a shared variable can be performed concurrently by multiple processors , But if it's a write to a shared variable , Only one processor can execute , In fact, the exclusive lock mechanism will ensure that only one processor can write .MESI It is one of the cache consistency protocols , These four letters represent four states respectively
M :Modified, In the cache line , The data read from the main memory is modified
E :Exclusive, Mutually exclusive or exclusive state , Currently only this cpu Get this variable in
S :Shared, Sharing status , There are multiple cpu This variable is obtained in the cache line in
I :Invalid, Failure state , If other cpu After modifying the value of cache line in , At present cpu The value in is dirty data , It needs to be set to failure 
working principle :cpu After startup, a monitoring mode will be adopted , Keep monitoring bus The transmission of messages in the bus . Anyone through bus The bus gets something from memory ,cpu You can feel .
1, Like a cpu0 To read variables x, First get variables from the bus x, If you are lock After prefix modification , Will be cpu0 Listening to the message being read , In read cpu A copy of this variable will be added , And the status set at this time is E, Exclusive state ;
2, If there is cpu1 Read this variable , Will also be in cpu1 Add a copy inside , And because there are many cpu At this time, you have a copy of this variable , Therefore, this state will be set to S Sharing status ;
3, If two cpu You have to modify the same variable , You need to be in every cpu Lock the cache line inside . If one of them cpu, Such as cpu0 Change the value of this variable , We need to go to bus The bus sends a message of modification , And tell cpu1 There are cache lines with the same variable , here cpu1 The data inside becomes dirty data , The status needs to be set to I, Failure state , And you need to read this new data from the main memory .bus The bus needs to decide which cpu You can get the qualification to modify this variable , If the bus decision fails , It will rise to the bus lock .
5.2,volatile There is no guarantee of atomicity
Combined with this MESI This Agreement , Let's analyze the previous one counter, You can clearly know why it is less than 100000 Time .
counter = 0; Threads A1 counter = 0; Threads B1 ...
counter = counter + 1; Threads A2 counter = counter + 1; Threads B2 ...
Here's the picture , stay cpu0 and cpu1 At the same time, copy this copy from main memory to working memory , And save it in the current cpu In the cache line of . Now two cpu We have to pay attention to this bus The bus sends a request to modify this variable ,bus The bus will judge which by the way of bus arbitration cpu Have the right to modify this variable , Mainly through the way of high and low potential , At this time cpu1 Get the execution right to modify this variable , Then the following third step will be performed , Execute at this time counter = counter + 1, And will tell others who have this variable cpu, Such as cpu0, This variable has been modified , here cpu0 Of counter Will also receive this notice , And will put the current counter Set to failure , And will discard it , Then the fourth step will not be implemented , In this way, I lost one counter++ The operation of , This leads to the sum less than 100000 了 .
Of course, this cpu0 This one inside counter It is not necessarily discarded , It may also be coverage .EMSI Only the consistency of this cache line can be guaranteed , But if this cpu0 Inside 1,4 The operation is already in this register , So this counter You don't have to go to this memory to get the latest value , It is also possible to get the latest value from the register . Whether it's overwriting or discarding , Can get the last counter The value is 1, It also explains this volatile This atomicity is not guaranteed .
6, summary
Through this JMM Memory model to regulate the access of shared variables in multithreaded scenarios , And through the operation of eight atoms , Standardize the execution steps of each thread . When multiple threads only need to ensure order and visibility , You can use this directly volatile, And through this EMSI Protocol to ensure cache consistency , That is, to explain in one sentence volatile Namely , Actively refresh the main memory , Force expiration of working memory for other threads
边栏推荐
- dtcloud 的消息机制(二)
- YOLOv5使用时遇到的问题
- Audio and video learning (VI) -- PCM audio Basics
- C language development environment construction: vscode+gcc
- Getting started with Scala
- 敏捷实践:开站会只问昨天做了什么?今天准备做什么就行了吗?
- 机器学习——支持向量机(SVM)
- Odoo multi company
- input获取焦点
- Comment comprendre le mécanisme de la mémoire et de l'attention dans l'apprentissage profond? Cette thèse de doctorat de 212 pages de Deakin vous donne une réponse.
猜你喜欢

《KG-BERT: BERT for Knowledge Graph Completion》

C language development environment construction: vscode+gcc

How to set various displays in 3dmax2021?

phpstorm2022连接数据库

音视频学习(七)——AAC音频码流

pytorch_lightning中lightning_logs里的hparams.yaml输出为空问题

字符串库函数和内存操作库函数详解及模拟实现

Message mechanism of dtcloud (3)

dtcloud Qweb实战之看板视图

032 SQL知识点小记
随机推荐
Dotnet Nuget 设置代理解决源不可访问的问题
音视频学习(七)——AAC音频码流
Summary of Lin Ziyu spark Scala programming
Is it safe to open an account online now? What certificates do I need to prepare to open an account?
Three methods are used to simulate the implementation of the library function strlen to deepen the understanding of strlen
Detailed explanation of odoo form view (I)
浙大等最新《深度学习新药设计》综述论文
Cao Jie spark programming Scala version after class exercise answers
phpstorm2022连接数据库
基于模型的强化学习综述
敏捷实践:开站会只问昨天做了什么?今天准备做什么就行了吗?
孤儿进程、僵尸进程和进程退出(针对面试)
Kanban view of dtcloud qWeb practice
容错、熔断的使用与扩展
机器学习和深度学习——归一化处理
Constraints of odoo
Hcip day 4 notes
Details of assets of odoo
Machine learning - support vector machine (SVM)
Introduction to odoo cli (1)