当前位置:网站首页>Volatile and JMM
Volatile and JMM
2022-06-27 14:35:00 【It takes time for fish to find water】
By volatile Decorated variables have two characteristics
visibility
After finish Flush back to main memory immediately and in time A notice , You can go to the main memory to get the latest version , The previous changes are visible to all subsequent threads
Orderliness
There is no data dependency , You can reorder
There is a data dependency , No reordering
But the rearranged instructions can never change the original serial semantics ! This must be taken into account in concurrent design !
When you write a volatile variable ,JMM The shared variable value in the local memory corresponding to the thread will be Flush back to main memory now in
When reading a volatile variable ,JMM Will set the local memory corresponding to this thread to be invalid , Read the latest shared variable in main memory again
therefore volatile The write memory semantics of is to refresh directly into main memory , The memory semantics of reading is to read directly from main memory
volatile Why visibility and order can be guaranteed
Memory barrier Memory Barrier
Memory barrier ( Also become a memory fence , Barrier order, etc , Is a kind of synchronous barrier instruction , yes CPU Or a synchronization point in the compiler's operation on random access to memory , Only after all the read and write operations before this point are executed can the operations after this point be started ), Avoid code reordering . Memory barrier is actually a kind of JVM Instructions ,Java The memory model rearrangement rules will requirement Java The compiler is generating JVM Insert a specific memory barrier instruction , Through these your memory barrier instructions ,volatile Realized Java Visibility and ordering in the memory model ( No rearrangement ), but volatile There is no guarantee of atomicity .
Before the memory barrier All of the Write operations Both Write back to main memory
Behind the memory barrier All of the Read operations Can get the latest results of all write operations before the memory barrier ( Visibility is achieved )
Write barriers (Store Memory Barrier) : Tell the processor to store all in the cache before writing the barrier (store bufferes) Data in is synchronized to main memory . That is, when you see Store Barrier directive , You must execute all the write instructions before the instruction before continuing to execute .
Reading barrier (Load Memory Barrier) : The read operation of the processor behind the read barrier , After reading the barrier . That is to say Load After the barrier instruction, it can ensure that the subsequent read data instruction can read the latest data .

So when reordering , It is not allowed to reorder the instructions after the memory barrier to the instructions before the memory barrier . In a word : To a volatile Variable writing , The antecedent happens to any subsequent pair of this volatile Variable reading , Also called reading after writing
Roughly divided into 2 Kind of
Reading barrier (Load Barrier): Insert a read barrier before reading instructions , Let working memory or CPU The cached data in the cache is invalid , Go back to main memory to get the latest data
Write barriers (Store Barrier): Insert a write barrier after writing instructions , Force data written to the buffer to be flushed back to main memory
| First action | Second operation : Ordinary reading and writing | Second operation :volatile read | Second operation :volatile Write |
|---|---|---|---|
| Ordinary reading and writing | You can rearrange | You can rearrange | You can't rearrange |
| volatitle read | You can't rearrange | You can't rearrange | You can't rearrange |
| volatitle Write | You can rearrange | You can't rearrange | You can't rearrange |
When the first act volatile Reading time , Whatever the second operation is , Can't reorder . This operation ensures that volatile After reading Operations of will not be rescheduled to volatile Before reading .
When the second drill does volatile Writing time , Whatever the first operation is , Can't reorder . This operation ensures that volatile Before writing Operations of will not be rescheduled to volatile After writing .
When the first act volatile Writing time , The second act volatile Reading time , Can't rearrange
Reading barrier : At every volatile Insert a... After the read operation LoadLoad barrier , Insert a after each read operation LoadStore barrier

Write barriers : At every volatile Insert a... After the write operation StoreStore barrier , Insert one after each inverted error StroeLoad barrier

JMM The memory barrier insertion strategy is divided into 4 Rules in

volatile characteristic
explain : Ensure that the results of different threads' operations on a variable are visible in time , That is, once the shared variable is changed, all threads are immediately visible .
Guaranteed visibility
Example
//static boolean flag = true;
static volatile boolean flag = true;
public static void main(String[] args)
{
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"\t -----come in");
while(flag)
{
}
System.out.println(Thread.currentThread().getName()+"\t -----flag Set to false, The program to stop ");
},"t1").start();
// Pause the thread for a few seconds
try {
TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {
e.printStackTrace(); }
flag = false;
System.out.println(Thread.currentThread().getName()+"\t Modified to complete flag: "+flag);
}
The above code : No addition volatile, No visibility , The program cannot stop
added volatile, Guaranteed visibility , The program can stop
The problem that the program cannot stop may be :
- The main thread has changed flag After that, it is not flushed to main memory , therefore t1 Threads can't see
- The main thread will flag Flushed to main memory , however t1 Always read from your working memory flag Value , There is no update in main memory to get flag The latest value ( Self working memory is private to each thread , Main memory is shared memory )
Desired results :
- After the thread modifies the copy in its working memory , Immediately flush it to main memory
- Every time a working variable is read in the working memory , Go to the main memory and read again , Then copy to working memory
solve :
Use volatile Decorate shared variables , You can achieve the above effect , By volatile The modified variables have the following characteristics :
- In the thread Read When , Each read will read the latest value of the shared variable in the main memory , Then copy it to working memory
- In the thread modify Copies of variables in working memory , It will be flushed to main memory immediately after modification
Java As defined in the memory model 8 Kind of Each thread has its own working memory And Between main physical memory Atomic operation of
read( Read )→load( load )→use( Use )→assign( assignment )→stroe( Storage )→write( write in )→lock( lock )→unlock( Unlock )

read: For main memory , Transfer the value of the variable from main memory to working memory , Main memory to working memory
load: Working memory , take read The variable values transferred from the main memory are put into the work Memory variable copy in , That is, data loading
use: Working memory , Pass the value of the working memory variable copy to the execution engine , whenever JVM This operation is performed when a bytecode instruction that requires the variable is encountered
assign: Working memory , Assign the value received from the execution engine to the working memory variable , whenever JVM This operation is performed when a bytecode instruction assigned to a variable is encountered
store: Working memory , Write the value of the assigned working variable back to the main memory
write: For main memory , take store The transferred variable value is assigned to the variable in main memory
Because of the above 6 One instruction can only guarantee the atomicity of a single instruction , Combinatorial atomic guarantee for multiple instructions , No large area locking , therefore ,JVM Two other atomic instructions are provided
lock: For main memory , Mark a variable as a thread exclusive state , Just lock it when writing , Just lock the process of writing variables
unlock: For main memory , Release a locked variable , Then it can be occupied by other threads
There is no atomicity
class MyNumber
{
volatile int number;
public void addPlusPlus() //synchronized
{
number++;
}
}
public class VolatileNoAtomicDemo
{
public static void main(String[] args)
{
MyNumber myNumber = new MyNumber();
for (int i = 1; i <=10; i++) {
new Thread(() -> {
for (int j = 1; j <=1000; j++) {
myNumber.addPlusPlus();
}
},String.valueOf(i)).start();
}
// Pause the thread for a few seconds
try {
TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {
e.printStackTrace(); }
System.out.println(myNumber.number); // The correct result should be :10000, The actual output is not
}
}

Without a lock , When a thread 1 Initiate... For main memory objects read Operate to write The time to operate the first set of processes , Threads 2 It is possible at any time for this Main memory object Initiate the second set of operations


about volatile Variables have visibility ,JVM Just make sure that the value loaded from main memory to thread working memory is new , It is only new when the data is loaded . But in a multithreaded environment ,” Data calculation “ and ” Data assignment “ The operation may occur more than once , If the data is loaded , If main memory volatile After the modification of modification variables , The operation in the thread working memory will be invalidated to read the latest value in the main memory ( It has visibility ), Write loss occurred during operation , namely The variables in the private memory and the public memory of each thread are not synchronized , This leads to inconsistent data . thus it can be seen volatile The solution is the visibility problem of variable reading , But atomicity is not guaranteed , Locking synchronization must be used in the scenario of multi-threaded modification of main memory shared variables .
Atomicity means that an operation is Non interruptible Of , Even in a multithreaded environment , Once an operation is started, it will not be affected by other threads .
public void add(){
i++; // It's not atomic , The operation is to read the value first , Then write back a new value , Equivalent to the original value plus 1, branch 3 Step through
}
If the second thread reads between the first thread reading the old value and writing back the new value i The domain value of , Then the second thread will see the same value as the first thread , And add the same value 1 operation , This creates thread safety issues , So for add Method must use synchronzed Decorate to ensure thread safety .
volatile Variables are not suitable for operations that depend on the current value
Instruction no rearrangement
Reordering is a means by which compiler and processor reorder instruction sequences in order to optimize program performance , Sometimes it will change the sequence of program statements , There is no data dependency , You can reorder
There is a data dependency , No reordering
But the instruction after the remake must not change the original serial semantics ! This must be taken into account in concurrent design !
Sorting and execution process of reordering

Data dependency : If two operations access the same variable , And one of these two operations is write operation , At this time, there is data dependency between the two operations .
| Before rearranging | After rearranging |
|---|---|
| int a = 1; // The first sentence int b = 2; // The second sentence int c = a + b; //3 | int b = 2; // The first sentence int a = 1; // The second sentence int c = a + b; //3 |
| Conclusion : Suppose the compiler adjusts the order of statements , But it doesn't affect the end result of the program . | Reorder OK |
The following example : If there is a data dependency , No reordering . After reordering occurs , Will cause the program to run differently
| - | Code | explain |
|---|---|---|
| Read after writing | a = 1; b = a; | After writing a variable , Read this variable again |
| Write after | a = 1; a = 2; | After writing a variable , Write this variable again |
| After reading | a = b; b = 1; | After reading a variable , Write this variable again |
volatile Use... Correctly
A single assignment can , But the assignment with compound operation cannot (i++ And so on )
// Single assignment volatile int a = 10; volatile boolean flag = false;Status flag : Determine whether the business is over
private volatile static boolean flag = true;
public static void main(String[] args) {
new Thread(()->{
while (flag){
//do something
}
},"t1").start();;
try {
Thread.sleep(2L);} catch (InterruptedException e) {
throw new RuntimeException(e);}
new Thread(()->{
flag = false;
},"t2").start();;
}
Low cost reading , Write lock strategy
/** * Use : When reading is far more than writing , Use a combination of internal locks and volatile Variable to reduce the overhead of synchronization * reason : utilize volatile Ensure the visibility of the read operation , utilize synchronized Ensure the atomicity of composite operation */ public class Counter{ private volatile int value; public int getValue(){ return value; // utilize volatile Ensure the visibility of the read operation } public synchronized int intcrement(){ return value++; // utilize synchronized Ensure the atomicity of composite operation } }DCL Release of double end lock (double-checked-locking)
Singleton mode in multithreading

volatile summary
1)volatile visibility
2)volatile There is no atomicity
3)volatile No rearrangement
4)volatile Add memory barrier at the bottom of keyword system , How the two are related
5) What is the memory barrier
6) Memory barrier function
7) Memory barrier four instructions
3 Sentence summary
1)volatile The operation before writing , It is forbidden to reorder to volatile after
2)volatile Operation after reading , It is forbidden to reorder to volatile Before
3)volatile After writing volatile read , No reordering
边栏推荐
- Domestic database disorder
- Synchronized与锁升级
- Design and implementation of reading app based on Web Platform
- Web chat room system based on SSM
- Pytorch learning 3 (test training model)
- SQL parsing practice of Pisa proxy
- Abnormal analysis of pcf8591 voltage measurement data
- 剑指 Offer II 039. 直方图最大矩形面积 单调栈
- Leetcode 724. 寻找数组的中心下标(可以,一次过)
- Sword finger offer II 039 Histogram maximum rectangular area monotonic stack
猜你喜欢

【PHP代码注入】PHP语言常见可注入函数以及PHP代码注入漏洞的利用实例

QT 如何在背景图中将部分区域设置为透明

赛迪顾问发布《“十四五” 关键应用领域之数据库市场研究报告》(附下载)

基于WEB平台的阅读APP设计与实现

【OS命令注入】常见OS命令执行函数以及OS命令注入利用实例以及靶场实验—基于DVWA靶场

SQL parsing practice of Pisa proxy
![[business security-04] universal user name and universal password experiment](/img/09/73d8356d00cefb6d1af086669f69ff.png)
[business security-04] universal user name and universal password experiment
机械硬盘和ssd固态硬盘的原理对比分析
![[PHP code injection] common injectable functions of PHP language and utilization examples of PHP code injection vulnerabilities](/img/19/9827a5e8becfc9d5bf2f51bddf803e.png)
[PHP code injection] common injectable functions of PHP language and utilization examples of PHP code injection vulnerabilities

请求一下子太多了,数据库危
随机推荐
Getting to know cloud native security for the first time: the best guarantee in the cloud Era
What are the operating modes of the live app? What mode should we choose?
At a time of oversupply of chips, China, the largest importer, continued to reduce imports, and the United States panicked
力扣 第 81 场双周赛
[WUSTCTF2020]girlfriend
2022-06-27日报:Swin Transformer、ViT作者等共话:好的基础模型是CV研究者的朴素追求
Synchronized与锁升级
海量数据!秒级分析!Flink+Doris构建实时数仓方案
Computer screen splitting method
enable_ if
The second part of the travel notes of C (Part II) structural thinking: Zen is stable; all four advocate structure
How to solve the problem of missing language bar in win10 system
Li Kou's 81st biweekly match
Gaode map IP positioning 2.0 backup
my. INI file configuration
【业务安全-02】业务数据安全测试及商品订购数量篡改实例
ERROR L104: MULTIPLE PUBLIC DEFINITIONS
基于Vue+Node+MySQL的美食菜谱食材网站设计与实现
Make a ThreadLocal (source code) that everyone can understand
ThreadLocal之强、弱、軟、虛引用