In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)06/01 Report--
This article will explain in detail how to use the Volatile keyword in Java. The content of the article is of high quality, so the editor will share it with you for reference. I hope you will have some understanding of the relevant knowledge after reading this article.
Volatile visibility commitment
The Java volatile keyword ensures the visibility of changing shared variables across threads. This may sound a little abstract, so let's elaborate on it.
In multithreaded applications, threads operate on non-volatile variables, and for performance reasons, each thread can copy them from main memory to the CPU cache as they are processed. If your computer contains more than one CPU, each thread can run on a different CPU. This means that each thread can copy the same variable to the CPU cache of a different CPU. This is closely related to the composition and working principle of the computer, and the cache module is included in every CPU because of performance considerations. Because the execution speed of CPU is much faster than that of memory (the memory here refers to Main Memory), because CPU has to read and write data, if it interacts with memory every time, then CPU spends a lot of time waiting for CPU O, and most of the time is stagnant and not really put into work. So in order to solve this problem, CPU cache is introduced. As shown in the following figure:
This leads to a problem that the same variable will be placed in its own cache by different CPU, and the read and write operations of the variable will be carried out in the cache. Of course, there is no problem with non-shared data, such as variables within the function, but for shared data, it will cause multiple CPU to manipulate the data, but other CPU does not know that the data has changed and still uses the old data, resulting in the program not meeting our expectations. Because CPU does not know which data in your program is multi-threaded shared data, and that data is not, if you do not tell CPU then it will default that the data is not shared, and each operates freely in its own cache. For example, this code:
Public class VolatileCase0 {public int counter = 0;}
This code is not safe in a multithreaded environment, and counter is a shared variable. Suppose two CPU work together on the same VolatileCase0 object, as shown in the following figure:
Currently, counter exists in both CPU caches, but the operation of each CPU to counter is not visible to the other CPU. Because we are not telling CPU and CPU that the counter is a shared memory variable at this time. To solve the problem of variable write visibility between multiple CPU caches, you need to modify the counter with the volatile keyword. The code is as follows:
Public class VolatileCase0 {public volatile int counter = 0;}
Let's take a look at an example program:
Public class VolatileCase1 {volatile boolean running = true; public void run () {while (running) {} System.out.println (Thread.currentThread (). GetName () + "end of execution");} public void stop () {running = false; System.out.println (Thread.currentThread (). GetName () + "thread Modified running to false") } public static void main (String [] args) throws Exception {VolatileCase1 vc = new VolatileCase1 (); Thread T1 = new Thread (vc::run, "Running-Thread"); Thread T2 = new Thread (vc::stop, "Stop-Thread"); t1.start (); TimeUnit.SECONDS.sleep (1); t2.start ();}}
If you do not add the volatile keyword to the running variable, the program will be stuck in "Running-Thread" and cannot be finished. After adding the volatile keyword, "Running-Thread" reads the modified running value, and the execution is finished.
Volatile prohibits instruction reordering
First of all, you need to explain what "instruction reordering" is. The so-called instruction reordering means that when CPU executes the program instructions, it will follow the order made by itself, not strictly according to the order written by the program code. The reason for this is also for performance reasons. CPU can provide overall efficiency by executing some instructions that can be executed first, rather than letting CPU waste all its time waiting. Interested readers can refer to this article:
Interested readers can also read the 64-ia-32-architectures-software-developer-vol-3a-part-1-manual development manual. Here are some descriptions of instruction reordering in the manual:
The term Memory Ordering refers to the order in which the processor issues reads (loads) and writes (stores) to system memory through the system bus. The Intel 64 and IA-32 architectures support multiple memory sorting models, depending on the implementation of the architecture. For example, the Intel386 processor enforces program sorting (often called strong sorting), and in any case, reads and writes are issued on the system bus in the order in which they occur in the instruction stream.
To optimize the performance of instruction execution, the IA-32 architecture allows for deviation from a strong sorting model called processor sorting in Pentium 4, Intel Xeon, and P6 series processors. These processor sorting variants (here called the memory sorting model) allow for performance-enhanced operations, such as allowing reads to take precedence over buffered writes. The purpose of these changes is to improve instruction execution speed while maintaining memory consistency, even in multiprocessor systems. We use a code to verify that CPU reorders instructions:
Public class MemoryOrderingCase1 {static int x = 0, y = 0, a = 0, b = 0; public static void main (String [] args) throws Exception {while (true) {CountDownLatch latch = new CountDownLatch (2); x = 0; y = 0; a = 0; b = 0 Thread T1 = new Thread (()-> {a = 1; x = b; latch.countDown ();}); Thread T2 = new Thread (()-> {b = 1; y = a; latch.countDown ();}) T1.start (); t2.start (); latch.await (); if (x = = 0 & & y = = 0) {System.out.println ("x =" + x + ", y =" + y + ", a =" + a + ", b =" + b); break;}
When x = 0 and y = 0, CPU executes the read instruction before the write instruction is completed.
Another example, Java Double checking locking singleton mode, is as follows:
Public class MemoryOrderingCase2 {private static volatile MemoryOrderingCase2 INSTANCE; int a; int b; private MemoryOrderingCase2 () {a = 1; b = 2;} public static MemoryOrderingCase2 getInstance () {if (MemoryOrderingCase2.INSTANCE = = null) {synchronized (MemoryOrderingCase2.class) {if (MemoryOrderingCase2.INSTANCE = = null) {MemoryOrderingCase2.INSTANCE = new MemoryOrderingCase2 () } return MemoryOrderingCase2.INSTANCE;}}
In this example, if INSTANCE removes the volidate keyword, it will cause a problem. Suppose two threads are accessing the getInstance () function, and the execution sequence is as follows:
1. Thread 1 enters the getInstance function, INSTANCE is null, and currently no thread holds the lock.
two。 Thread 1 again determines whether INSTANCE is null, and the result is true.
3. Thread 1 executes INSTANCE = new MemoryOrderingCase2 ().
4. Thread 1 executes new MemoryOrderingCase2 ().
5. Thread 1 allocates space for objects in heap memory.
6. Thread 1 INSTANCE points to the object, and INSTANCE is no longer null.
7. The thread 1 new MemoryOrderingCase2 () object starts the initialization process, calls the parent class constructor, assigns values to some properties, and so on.
8. Thread 2 enters the getInstance function, determines that INSTANCE is not null, and returns INSTANCE.
The problem here is that the MemoryOrderingCase2 object is leaked to the outside world by thread 2 before it has completed its initialization process. This means that the read operation occurs before the write operation is completed.
View part of the assembly code for the getInstance () function:
0x0000000003a663f4: movabs $0x7c0060828% RDX {metadata ('org/blackhat/concurrent/date20200312/MemoryOrderingCase2')} 0x0000000003a663fe: mov 0x60 (% R15),% rax 0x0000000003a66402: lea 0x18 (% rax),% rdi 0x0000000003a66406: cmp 0x70 (% R15),% rdi 0x0000000003a6640a: ja 0x0000000003a66557 0x0000000003a66410: mov% rdi,0x60 (% R15) 0x0000000003a66414: mov 0xa8 (% rdx),% rcx 0x0000000003a6641b: mov% rcx, (% rax) 0x0000000003a6641e: mov% rdx,%rcx 0x0000000003a66421: shr $0x3t% RCX 0x0000000003a66425: mov% ecx 0x8 (% rax) 0x0000000003a66428: xor% rcx,%rcx 0x0000000003a6642b: mov% ecx,0xc (% rax) 0x0000000003a6642e: xor% rcx,%rcx 0x0000000003a66431: mov% rcx,0x10 (% rax) * new;-org.blackhat.concurrent.date20200312.MemoryOrderingCase2::getInstance@17 (line 24) 0x0000000003a66435: movl $0x1 rax 0xc (% rax); * putfield a;-org.blackhat.concurrent.date20200312.MemoryOrderingCase2::@6 (line 16) -org.blackhat.concurrent.date20200312.MemoryOrderingCase2::getInstance@21 (line 24) 0x0000000003a6643c: movl $0x2 rax 0x10 (% rax); * putfield b;-org.blackhat.concurrent.date20200312.MemoryOrderingCase2::@11 (line 17) -org.blackhat.concurrent.date20200312.MemoryOrderingCase2::getInstance@21 (line 24) 0x0000000003a66443: movabs $0x76b907160pr% RSI {oop (a 'java/lang/Class' =' org/blackhat/concurrent/date20200312/MemoryOrderingCase2')} 0x0000000003a6644d: mov% rax,%r10 0x0000000003a66450: shr $0x30x0000000003a6645c% R10 0x0000000003a66454: mov% r10d0x0000000003a6645c 0x68 (% rsi) 0x0000000003a66458: shr $0x9 0x0000000003a6645c% RSI 0x0000000003a6645c: movabs $0xf6fd0000x0000000003a6645c% Rax 0x0000000003a66466: movb $0x0, (% rsi,%rax,1) 0x0000000003a6646a: lock addl $0x0, (% rsp) * putstatic INSTANCE;-org.blackhat.concurrent.date20200312.MemoryOrderingCase2::getInstance@24 (line 24) this is the end of sharing about how to use the Volatile keyword in Java. I hope the above content can be helpful to you and learn more. If you think the article is good, you can share it for more people to see.
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.