In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces "what are the Volatile-related knowledge points in Java". In daily operation, I believe many people have doubts about Volatile-related knowledge points in Java. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful for you to answer the questions about "what are the Volatile-related knowledge points in Java?" Next, please follow the editor to study!
The usage of 1.volatile
The volatile keyword is the "lightest synchronization mechanism" provided by the Java virtual machine. It appears as a modifier to "decorate variables", but local variables are not included here. Let's take a look at a demo. The code is as follows:
/ * * @ Author Little Boy picking up Field snails * @ Date 2020-08-02 * @ Desc volatile visibility Exploration * / public class VolatileTest {public static void main (String [] args) throws InterruptedException {Task task = new Task (); Thread T1 = new Thread (task, "Thread T1") Thread T2 = new Thread (new Runnable () {@ Override public void run () {try {Thread.sleep (1000); System.out.println ("start notifying the thread to stop"); task.stop = true; / / modify the value of the stop variable. } catch (InterruptedException e) {e.printStackTrace ();}, "thread T2"); t1.start (); / / start thread T1 t2.start (); / / start thread T2 Thread.sleep (1000);}} class Task implements Runnable {boolean stop = false; int i = 0 @ Override public void run () {long s = System.currentTimeMillis (); while (! stop) {iTunes;} System.out.println ("thread exit" + (System.currentTimeMillis ()-s));}}
"run result:"
You can see that thread T2, although stop is set to true, thread T1 is invisible to the "stop variable" of T2, so it is always in the endless loop running. If the variable stop is modified with volatile, thread T1 can be stopped, and the running result is as follows:
Volatile boolean stop = false
2. The role of vlatile modification variables.
From the above example, we can see that the variable stop, with vlatile modification, thread T1 is visible to stop. In fact, the purpose of vlatile is to "ensure the visibility of variables to all threads." Of course, vlatile also has the function of "prohibiting instruction rearrangement", but it "does not guarantee atomicity".
So when the interviewer asks you "what are the functions or features of volatile", you can answer like this:
Ensure that variables are visible to all threads
Prohibit instruction reordering
Atomicity is not guaranteed
3. Memory model of modern computer (computer model, MESI protocol, sniffing technology, bus)
To better understand volatile, let's review the computer's memory model and JMM (Java memory model).
Computer model when a computer executes a program, the instructions are executed by the CPU processor, and the data you are dealing with is in the main memory.
Due to the difference of several orders of magnitude between the computing speed of the computer's storage device and the processor, it is impossible for the CPU to finish executing instructions and then wait for the main memory to access the data slowly, so modern computer systems add a cache (Cache) whose read and write speed is close to the processor's computing speed as a buffer between the memory and the processor.
In multiprocessor systems, each processor has its own cache, and they share the same main memory. The computer Abstract memory Model is as follows:
When the program is executed, the data needed is copied from the main memory to the cache.
When the CPU processor calculates, it reads from its cache and writes the calculated data to the cache.
When the program operation is finished, the cached data is refreshed to the main memory.
With the development of science and technology, caching has given rise to primary cache (L1), secondary cache (L2), and even tertiary cache (L3) for efficiency.
When the computing tasks of multiple processors involve the same main memory area, it may lead to the problem of "inconsistent cache data". How to solve this problem? There are two options.
❝1. By adding LOCK# locks on the bus.
2. Through the cache consistency protocol (Cache Coherence Protocol) ❞
Bus
❝bus (Bus) is a common communication trunk that transmits information between various functional components of a computer. It is a transmission harness composed of wires. According to the types of information transmitted by the computer, the computer bus can be divided into data bus, address bus and control bus, which are used to transmit data, data address and control signals respectively. ❞
CPU and other functions communicate through the bus, and if LOCK# locks are added to the bus, other CPU cannot access memory while the bus is locked, which makes it "less efficient".
In order to solve the problem of consistency, MESI protocol can also use cache consistency protocol. In other words, each processor follows some protocols when accessing the cache, and operates according to the protocols when reading and writing, such as MSI, MESI (IllinoisProtocol), MOSI, Synapse, Firefly and DragonProtocol. The more famous is Intel's MESI (Modified Exclusive Shared Or Invalid) protocol, whose core idea is:
❝when CPU writes data, if it is found that the operating variable is a shared variable, that is, a copy of the variable also exists in other CPU, it will send a signal to other CPU to set the cache row of the variable into an invalid state, so when other CPU needs to read the variable, it will re-read it from memory if it finds that the cache line caching the variable in its own cache is invalid. ❞
Learn about the four states (M, E, S, I) of each cache line tag in CPU:
Cache state description M, modified (Modified) the cache line is only cached by the CPU. Unlike the value of main memory, it is written to memory before it is read by other CPU and set to SharedE. The exclusive (Exclusive) cache line is only cached by the CPU, which is the same as the value of main memory. It is set to Shared when read by other CPU, ModifiedS when written by other CPU, and shared (Shared) by multiple CPU caches. The data in each cache is the same as the main memory data. Invalid (Invalid) the cache row data is invalid and needs to be reloaded from the main memory if needed.
How is the MESI protocol implemented? How to ensure that the current processor's internal cache, main memory and cache data of other processors are consistent on the bus? "multiprocessor bus sniffing"
Sniffing technology
❝under multiprocessors, in order to ensure that the cache of each processor is consistent, the cache consistency protocol will be implemented. Each processor checks whether its cache value has expired by sniffing the data propagated on the bus. If the processor finds that the memory address of its cache line has been modified, it will set the cache line of the current processor to an invalid state. When the processor modifies this data, it re-reads the database from the system memory into the processor cache. ❞
4. Java memory Model (JMM)
The Java virtual machine specification attempts to define a Java memory model to "shield the memory access differences between various hardware and operating systems", so that Java programs can achieve consistent memory access on various platforms.
The Java memory model is analogous to the computer memory model.
For better execution performance, the java memory model does not restrict the execution engine from using processor-specific registers or caches to deal with main memory, nor does it restrict the compiler to adjust code order optimization. So the Java memory model "will have cache consistency problems and instruction reordering problems".
The Java memory model states that all variables are stored in main memory (similar to physical memory in a computer model), and each thread has its own working memory (similar to the cache of a computer model). The "variables" here include instance variables and static variables, but "do not include local variables" because local variables are thread private.
The thread's working memory holds a copy of the main memory of the variable used by the thread. "all operations on the variable by the thread must be carried out in the working memory", rather than directly manipulating the main memory. And each thread cannot access the working memory of other threads.
For example, assuming that the initial value of I is 0, execute the following statement:
I = iFig 1
First, the execution thread T1 reads from the main memory to iExten0 and to the working memory. Then in the working memory, assign iSecret1, and the working memory gets iSecret1, and finally writes the result back to the main memory. Therefore, if it is a single thread, there is no problem with the execution of the statement. However, the local working memory of thread T2 has not expired, so the data it reads is dirty data. As shown in the figure:
The Java memory model is built around how to deal with the three characteristics of "atomicity, visibility and order" in the process of concurrency. Let's review together.
5. Three features of concurrent programming (atomicity, visibility, ordering)
Atomicity
Atomicity, which means that the operation is uninterruptible, either completed or not executed, and the access, read and write of the basic data types are atomic, of course (except for the non-atomic protocols of long and double). Let's take a look at a few examples:
I = 666; / / statement 1 I = j; / / statement 2 I = iDefinition1; / / statement 3 iComplications; / / statement 4
The statement 1 operation is obviously atomic, assigning the value 666 to I, that is, when the thread executes the statement, it writes the value 666 directly into working memory.
Statement 2 operation also appears to be atomic, but it actually involves two operations, first reading the value of j, and then writing the value of j to working memory. The two operations are atomic operations separately, but together they do not satisfy atomicity.
Statement 3 reads the value of I, adds 1, and writes it back to main memory. This is not an atomic operation.
Statement 4 is equivalent to statement 3 and is also a non-atomic operation.
Visibility
Visibility means that when one thread modifies the value of a shared variable, other threads are immediately aware of the change.
The Java memory model achieves visibility by synchronizing the new value back to the main memory after the variable is modified and refreshing the variable value from the main memory before the variable is read, which relies on the main memory as the transmission medium, whether it is an ordinary variable or a volatile variable.
The volatile variable ensures that the new value can be synchronized back to the main memory immediately and refreshed from the main memory immediately before each use, so we say that volatile ensures the visibility of multithreaded operation variables.
Synchronized and Lock also guarantee visibility, and the thread flushes the shared variable values back to main memory before releasing the lock. Final can also achieve visibility.
Order
The Java virtual machine describes the ordering of Java programs in this way: if you observe within this thread, all operations are orderly; if you are in one thread, looking at another thread, all operations are disordered.
The second half of the sentence means that in the Java memory model, "allowing compilers and processors to reorder instructions" will affect the correctness of multithreaded concurrent execution; the first half of the sentence means the semantics of "as-if-serial", that is, no matter how much reordering (compiler and processor to improve parallelism), the execution result of (single-threaded) programs will not be changed.
For example, the following program code:
Double pi = 3.14; / / A double r = 1.0; / / B double area = pi * r * r; / / C
Step C depends on steps An and B, because the instruction rearrangement exists, the program execution sequence may be A-> B-> C, or B-> A-> C, but C cannot be executed before An or B, which will violate the as-if-serial semantics.
Look at a piece of code. Suppose the program executes the read method first, and then the add method. The result must be the output sum=2.
Bool flag = false; int b = 0; public void read () {b = 1; / 1 flag = true; / / 2} public void add () {if (flag) {/ / 3 int sum = breadb; / / 4 System.out.println ("bb sum is" + sum);}}
If it is single-threaded, the result should be fine. If it is multithreaded, thread T1 "reorders" instructions on steps 1 and 2? As a result, sum is not 2, but 0, as shown in the following figure:
Why is that? "instruction reordering" means that during program execution, "to improve performance," the compiler and CPU may reorder instructions. CPU reordering includes instruction parallel reordering and memory system reordering. The reordering types and reordering procedures are as follows:
In fact, you can add the volatile keyword to flag to ensure orderliness. Of course, orderliness can also be ensured through synchronized and Lock. Synchronized and Lock guarantee that only one thread executes synchronous code at a time, which is equivalent to letting threads execute program code sequentially, which naturally ensures orderliness.
In fact, the ordering of Java memory model does not rely solely on volatile, synchronized and Lock to ensure ordering. This is because there is a prior occurrence principle (happens-before) in the Java language:
"Program order rules": within a thread, according to the order of control flow, the operation written in front occurs first in the operation written later.
"Pipe locking rule": a unLock operation occurs first on the same lock forehead lock operation
"volatile variable rule": the write operation to a variable occurs first in the subsequent read operation on the variable.
Thread start rules: the start () method of the Thread object occurs first in each action of this thread
"Thread termination Rule": all operations in a thread first occur in the termination detection of the thread. We can detect that the thread has terminated execution through the end of the Thread.join () method and the return value of Thread.isAlive ().
Thread interrupt Rule: the call to the thread interrupt () method first occurs in the code of the interrupted thread to detect the occurrence of the interrupt event
Object termination rules: the initialization of an object occurs first at the beginning of its finalize () method
Transitivity: if operation An occurs first in operation B, and operation B occurs in operation C first, it can be concluded that operation An occurs in operation C first.
According to the eight rules of happens-before, let's go back to the example and analyze it together. Add the volatile keyword to flag, how does look look ensure orderliness?
Volatile bool flag = false; int b = 0; public void read () {b = 1; / 1 flag = true; / / 2} public void add () {if (flag) {/ / 3 int sum = breadb; / / 4 System.out.println ("bb sum is" + sum);}}
First of all, flag plus the volatile keyword, which forbids instruction rearrangement, that is, 1 happens-before 2
According to the volatile variable rules, 2 happens-before 3
From the rules of procedure order, we can get 3 happens-before 4.
Finally, from the transitivity, we get 1 happens-before 4, so we can output sum=2 properly.
Basic principle of 6.volatile
As we have learned from the above discussion, we know that the semantics of volatile is to ensure the visibility of variables to all threads and to prohibit instruction rearrangement optimization. So how does its underlying layer ensure visibility and prohibit instruction rearrangement?
Figure out how volatile ensures visibility?
Here, take a look at some pictures first, ~
Assuming the initial value of the flag variable, false, which now has two threads T1 and T2 to access, it can be simplified to the following figure:
If thread T1 executes the following code statement and flag has no volatile modification; T1 has just modified the value of flag and has not had time to refresh it to the main memory, T2 comes to read it again, and the data flag is easily inconsistent, as shown below:
Flag=true
If the flag variable is modified by volatile, it is different. If thread T1 modifies the modified value, volatile can guarantee that the modified flag variable can be "synchronized back to main memory immediately". As shown in the figure:
Careful friends will find that thread T2 is still the old value of flag, isn't that a problem? In fact, volatile has another guarantee, that is, "refresh the latest value from the main memory immediately before each use". After thread T1 is modified, the variable copy of thread T2 will expire, as shown in the figure:
Obviously, this is not the bottom layer yet. in fact, volatile's visibility and prohibition of instruction rearrangement are all related to the "memory barrier". Let's compile the code related to volatile.
DCL singleton Mode (volatile) & Compiler comparison
The DCL singleton mode (Double Check Lock, double-checked lock) is more commonly used, and it needs to be modified by volatile, so compile it with this code.
Public class Singleton {private volatile static Singleton instance; private Singleton () {} public static Singleton getInstance () {if (instance = = null) {synchronized (Singleton.class) {if (instance = = null) {instance = new Singleton ();} return instance;}}
After compiling this code, looking at the assembly code generated by instance with and without the volatile keyword, it is found that when modified by the volatile keyword, there will be an extra lock addl $0x0, (% esp), that is, an extra lock prefix instruction
0x01a3de0f: mov $0x3375cdb0c1ee09 0x01a3de1d% esi;... beb0cd75 33; {oop ('Singleton')} 0x01a3de14: mov% eax,0x150 (% esi);... 89865001 0000 0x01a3de1a: shr $0x9 0x01a3de1a% ESI;... c1ee09 0x01a3de1d: movb $0x0dagol 0x1104800 (% esi);... c6860048 100100 0x01a3de24: lock addl $0x0, (% esp) .. f0830424 00; * putstatic instance;-Singleton::getInstance@24
The lock instruction acts as a "memory barrier" that guarantees the following:
❝1. When reordering, you cannot reorder subsequent instructions to the position in front of the memory barrier.
two。 Write the cache of this processor to memory
3. If it is a write action, it will invalidate the corresponding cache in other processors. ❞
Obviously, points 2 and 3 are the embodiment of volatile's guaranteed visibility, and the first point is the prohibition of instruction rearrangement.
Memory barrier four categories of memory barrier: (Load stands for read instruction, Store for write instruction)
Memory barrier
The memory barrier type abstract scenario describes the LoadLoad barrier Load1; LoadLoad; Load2 to ensure that the data to be read by Load1 is read before the data to be read by Load1 is accessed. The StoreStore barrier Store1; StoreStore; Store2 ensures that the write operation of the Store1 is visible to other processors before the Store2 write is executed. The Load1; LoadStore; Store2 ensures that the data to be read by the Load1 is read before the Store2 is written. StoreLoad barrier Store1; StoreLoad; Load2 ensures that writes to the Store1 are visible to all processors before the Load2 read operation is performed.
In order to implement the memory semantics of volatile, the Java memory model adopts the following conservative strategies
Insert a StoreStore barrier in front of each volatile write operation.
Insert a StoreLoad barrier after each volatile write operation.
Insert a LoadLoad barrier in front of each volatile read operation.
Insert a LoadStore barrier after each volatile read operation.
Some friends may still be a little confused about this, because the memory barrier is too abstract. Let's take a look at the code:
The memory barrier ensures that the previous instructions are executed first, so this ensures that instruction rearrangement is prohibited, while the memory barrier ensures that cache writes to memory and other processor caches fail, which ensures visibility, ~
Typical scenarios of 7.volatile
Generally speaking, the following two conditions are required to use volatile:
1) the write operation to the variable does not depend on the current value
2) this variable is not included in the invariant with other variables
In fact, volatile scenarios are generally "status flags" and "DCL singleton mode".
7.1 status Fla
In-depth understanding of the Java virtual machine, the examples in the book:
Map configOptions; char [] configText; / / this variable must be defined as volatile volatile boolean initialized = false; / / suppose the following code runs / / simulates reading configuration information in thread A, and sets initialized to true after reading to tell other threads that the configuration is available: configOptions = new HashMap (); configText = readConfigFile (fileName); processConfigOptions (configText, configOptions); initialized = true / / suppose the following code runs / / waits for initialized to be true in thread B, which means that thread A has initialized the configuration information while (! initialized) {sleep ();} / / uses the initialized configuration information doSomethingWithConfig () in thread A.
7.2 DCL singleton mode
Class Singleton {private volatile static Singleton instance= null; private Singleton () {} public static Singleton getInstance () {if (instance==null) {synchronized (Singleton.class) {if (instance==null) instance= new Singleton ();}} return instance;}}
8. Volatile related classic interview questions
Talking about the characteristics of volatile
Memory semantics of volatile
Talk about the three features of concurrent programming
What is memory visibility and what is order reordering?
How does volatile solve the problem of visibility in java concurrency
How to prevent instruction rearrangement in volatile
Can volatile solve atomicity? Why?
The underlying implementation mechanism of volatile
The difference between volatile and synchronized?
8.1 talk about the characteristics of volatile
Memory semantics of 8.2 volatile
When you write a volatile variable, JMM flushes the value of the shared variable in the local memory corresponding to the thread to the main memory.
When reading a volatile variable, JMM sets the local memory for that thread to be invalid. The thread then reads the shared variable from the main memory.
8.3 talk about the three features of concurrent programming
Atomicity
Visibility
Order
8.4 what is memory visibility and what is order reordering?
Visibility means that when one thread modifies the value of a shared variable, other threads are immediately aware of the change.
Instruction rearrangement refers to the reordering of existing instructions when JVM compiles Java code, or when CPU executes JVM bytecode.
8.5 how does volatile solve the problem of visibility in java concurrency
The bottom layer is achieved through the memory barrier. Volatile can guarantee that after the modified variables, you can immediately synchronize back to the main memory and refresh the latest values from the main memory immediately before each use.
8.6 how to prevent instruction rearrangement in volatile
It's also a memory barrier. Tell the interviewer about the conservative strategy of Java memory:
Insert a StoreStore barrier in front of each volatile write operation.
Insert a StoreLoad barrier after each volatile write operation.
Insert a LoadLoad barrier in front of each volatile read operation.
Insert a LoadStore barrier after each volatile read operation.
Let's talk about the semantics of volatile. When reordering, you can't reorder the instructions behind the memory barrier to the position before the memory barrier.
Can 8.7 volatile solve atomicity? Why? No, you can directly take the example of iTunes +. Atomicity needs to be guaranteed by synchronzied or lock.
Public class Test {public volatile int race = 0; public void increase () {race++;} public static void main (String [] args) {final Test test = new Test ()
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.