Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use the JMM and volatile keywords in Java

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

Java JMM and volatile keywords how to use, many novices are not very clear about this, in order to help you solve this problem, the following small series will explain in detail for everyone, there are people who need this to learn, I hope you can harvest.

Java memory model

With the rapid development of computer CPU, CPU computing power has far exceeded the ability to read data from the main memory (running memory), in order to solve this problem, CPU manufacturers designed a CPU built-in cache area. The addition of cache makes CPU read data directly from cache during operation, which solves the performance problem to some extent. But it also raises another problem, in the case of CPU multicore, where each processor has its own cache, how to maintain data consistency. In order to ensure data consistency of multi-core processors, protocols for data consistency of multi-core processors are introduced, including MOSI, Synapse, Firefly, Dragon Protocol, etc.

When the JVM executes multithreaded tasks, shared data is stored in main memory. Each thread (executing different processors) has its own cache. When a thread modifies shared data, it first copies it from main memory to the thread cache. After modification, it copies it from cache to main memory. When multiple threads perform such operations, unexpected errors in shared data can result.

For example:

i++;//operation

For this i++ operation, the thread first reads the value of i from main memory, such as i=0, then copies it to its own cache, performs the i++ operation, and finally copies the result of the operation from cache to main memory. If two threads pass through operation i++, the expected result is 2. Is it really 2? The answer is no. Thread 1 reads i=0 in main memory and copies it to its cache. Thread 2 also reads i=0 and copies it to its cache. Perform i++ operation. How can the structure finally be 1 instead of 2?

To solve the cache inconsistency problem, there are two solutions:

Locks on the bus mean that only one thread can perform i++ operations (including reads, modifications, etc.) at a time.

Cache Coherence Protocol

The first way is not much to say, it is synchronous code block or synchronous method. Only one thread can read and modify shared data, and the other threads are in thread blocking state.

The second method is cache coherency protocol, such as Intel's MESI protocol, its core idea is that when a processor writes variable data, if other processors also have this variable, it will send a semaphore to inform the processor that the cached data is set to invalid state. When other processes need to read the variable, it is read back from main memory and copied to cache.

The concept of programming

There are three concepts of concurrent programming, including atomicity, visibility, and orderliness.

atomicity

Atomicity means that if the operation is atomic, it either succeeds or fails, and there is no third case. For example:

String s="abc";

This complex operation is atomic. Another example:

int i=0;i++;

i=0 This is an assignment operation, this step is atomic; is i++ atomic? Of course not, first it needs to read i=0, then it needs to perform the operation, write the new value of i 1, it contains two steps of reading and writing, so it is not atomic operation.

visibility

Visibility refers to when sharing data, one thread modifies the data, and other threads know that the data has been modified and will re-read the latest main memory data.

For example:

i=0;//main memory i++;//thread 1j=i;//thread 2

Thread 1 modifies i but doesn't copy i to main memory, thread 2 reads i and assigns i to j, we expect j=1, but since thread 1 modifies i and doesn't copy it to main memory, thread 2 reads i and assigns j, j has a value of 0.

That is, the value of thread i is modified without the other threads knowing it.

orderliness

Ordering refers to the ordering of code execution because code may undergo instruction reorder.

The Java language provides two keywords, volatile and synchronized, to order thread code operations. Volatile is because it contains the semantics of "prohibiting instruction reordering." Synchronized executes code in a single thread. Regardless of whether the instructions are rearranged or not, the final execution result is consistent.

Volatile Detailed Explanation of Volatile Keyword Role

The variable modified by the volatile keyword plays two roles:

1. A thread modifies a variable modified by the volatile keyword Yes, according to the protocol of data consistency, by semaphore, changes the state of the volatile keyword modifier variable in the cache of other threads to an invalid state. If other threads need to rewrite the variable, they will read it again from main memory instead of reading it from their own cache.

2. Variables modified by the volatile keyword do not instruct reordering.

volatile guarantees visibility and prevents instruction rearrangement

In Java concurrent programming, there is such a book

public class NoVisibility { private static boolean ready; private static int a; public static void main(String[] args) throws InterruptedException { new ReadThread().start(); Thread.sleep(100); a = 32; ready = true; } private static class ReadThread extends Thread { @Override public void run() { while (! ready) { Thread.yield(); } System.out.println(a); } }}

In the above code, it is possible (very unlikely, but possible) that the value of a will never be printed because the ReadThread reads the ready-in-main memory as false, and the ready-in-main thread updates ready-but not readThread cache.

In addition:

a = 32;

ready = true;

These two lines of code are subject to instruction rearrangement. That is, you can print a value of 0.

If you add the volatile keyword to the variable, you can prevent the above two abnormal situations from happening.

Volatile does not guarantee atomicity

First test with a piece of code, open 10 threads, these 10 threads share a variable inc (volatile decoration), and in each thread loop 1000 times inc+ operation. Our expected result is 10,000.

public class VolatileTest { public volatile int inc = 0; public void increase() { inc++; } public static void main(String[] args) throws InterruptedException { final VolatileTest test = new VolatileTest(); for (int i = 0; i

< 10; i++) { new Thread(() ->

{ for (int j = 0; j < 1000; j++) test.increase(); }).start(); } //make sure all previous threads are executed Thread.sleep(3000); System.out.println(test.inc); }}

Run main multiple times and you'll find that the result will never be 10000, it's always less than 10000. There may be such a question, volatile guarantees the visibility of shared data, thread 1 modifies the inc variable thread 2 will re-read from main memory, so that can ensure the correctness of inc++ ah, but why did not we get the expected results?

As we have seen before, an operation like inc++ is not an atomic operation; it is read, add, and write. In one case, when thread 1 reads the value of inc, it has not modified it, thread 2 also reads it, thread 1 has finished modifying it, and thread 2 is notified that the cached value of inc needs to be reread, but it does not need to read inc at this time, it still performs the write operation, and then assigns it to the main thread. At this time, the data will have problems.

Volatility does not guarantee atomicity. And you need to lock it to make sure that if you add synchronized to the increment method, the result of rerunning the print is 10000.

public synchronized void increase() { inc++;}volatile's usage scene status tag

The most common usage scenario for volatile is the status tag, as follows:

private volatile boolean asheep ;//Thread 1while(! asleep){ countSheep();}//Thread 2asheep=true; volatile boolean initialized = false;//Thread 1:context = loadContext(); initialized = true; //If the above two lines of code are not modified with volatile, instruction rearrangement may occur, resulting in an error//Thread 2:while(!) inited ){sleep()}doSomethingwithconfig(context); Did it help you after reading the above? If you still want to have further understanding of related knowledge or read more related articles, please pay attention to the industry information channel, thank you for your support.

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.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report