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 introduces you to the relevant knowledge and principles of JavaCAS, the content is very detailed, interested friends can refer to, hope to be helpful to you.
JMM and problem introduction
Why talk about JMM first, because the variables maintained in the implementation class of CAS are modified by volatile. This volatile is implemented in accordance with the JMM specification (not 100%, as we will see below) to ensure that multiple threads concurrently access a variable to achieve thread safety.
A series of knowledge points slowly.
First of all, what is JMM? JMM is what is called the memory model of java. It is a logical partition made by people, or JMM can be regarded as a specification. What are the specifications? As follows
Visibility: after a thread makes changes to a variable in memory, it requires other threads to be notified immediately within the first event. In the implementation of CAS, visibility is actually notified through constant while loop reads, rather than passively notified atomicity: threads either succeed or fail together when performing an operation: ordering: to improve performance The compiler processor will reorder instructions, source code-> compiler optimization rearrangement-> processor optimization rearrangement-> memory system rearrangement-> finally executed command
The entity that JVM runs is a thread. After each thread is created, JVM will create a workspace for it. This workspace is a private space between each thread, and none of the two threads can directly access each other's workspace. The communication between threads must be completed through the shared space.
JMM stipulates that all variables are stored in main memory, and the main memory is a piece of shared space, so what if a thread makes changes to the shared variables in main memory? Like
It goes like this:
Copy a copy of a shared variable to the workspace to modify the assignment of the variable and write the variable in the workspace back to memory
The JMM also stipulates the following:
Any thread must immediately refresh the shared variables of the workspace into memory before unlocking it. Before adding the lock, the thread must read the value in the main memory and update it to its own workspace. Locking and unlocking is the same lock.
Problem introduction
At this time, if multiple threads concurrently follow the above three steps to access shared variables in main memory, there will be thread safety problems. For example, now the shared variable in main memory is clocked 1, and two threads of AB want to access this c variable concurrently. Now A copies c to its own workspace for caching, so thread 2, thread B also carries out C++ at the same time C in the workspace of B = 2, the AB thread writes the result back to the workspace, and the final result is 2, not the 3 we expected.
I believe that how to solve this problem, as we all know, is to use JUC, the atomic class in can avoid this problem.
The underlying implementation of atomic classes uses CAS technology.
What is CAS?
CAS (compare and swap) is just as its name implies: comparison and exchange, the bottom layer of atomic classes in JUC uses CAS lock-free to achieve thread safety, which is a very cool technology.
As in the following two lines of code, compare and then swap, that is, if the value read from the main memory is 4, update it to 2019
AtomicInteger atomicInteger = new AtomicInteger (4); atomicInteger.compareAndSet (4Jing 2019)
The source code to follow up AtomicInteger is as follows. The underlying maintenance is a variable of type int (of course, because the original class I chose is of type AtomicInteger), and the value of this type of int is modified by volatile.
Private volatile int value; / * *
* Creates a new AtomicInteger with the given initial value. *
* @ param initialValue the initial value *
/ public AtomicInteger (int initialValue) {value = initialValue
}
What is volatile?
Volatile is a lightweight synchronization mechanism provided by JVM. Why the lightweight sector? as mentioned above, there are three features mentioned in the JMM specification, while the volatile provided by JVM only meets the 2max 3 in the above specification, as follows:
Guaranteed visibility does not guarantee atomicity prohibit instruction reordering
Volatile alone cannot satisfy atomicity, that is, the following code will still have thread safety problems in the case of multithreaded concurrent access.
Private volatile int value; public void add () {value++;}
So how does the atomic class of JUC be implemented to satisfy atomicity? So I have to say that the protagonist of this blog post, CAS
CAS source code follow-up
Let's follow up the incrementing and then getting method incrementAndGet () in AtomicInteger.
Public final int incrementAndGet () {return unsafe.getAndAddInt (this, valueOffset, 1) + 1;}
Through the code, we see that the Unsafe class is called to implement the
What is the Unsafe class?
When you enter the Unsafe class, you can see that there are a large number of native methods in it, and these native methods are all empty methods.
This unsafe class is actually equivalent to a backdoor. The method for java to access and call the C C++ function class library on the system is as follows
Continue to follow this method incrementAndGet (), so we come to our protagonist method, about this method is not difficult to understand, mainly to figure out what the var12345 in the method stands for, as follows: code + comments
Var1: passed in by the last method: this, the current object
Var2: the valueOffset passed in by the last method is the memory address offset. Through this memory address offset, I can find exactly the address of the variable I want to operate on in memory.
Var4: the 1 passed in the last method is the value of each increment.
Var5: the target value in the current memory read through this and memory address offset
Public final int getAndAddInt (Object var1, long var2, int var4) {int var5
Do {var5 = this.getIntVolatile (var1, var2)
} while (! this.compareAndSwapInt (var1, var2, var5, var5 + var4))
Return var5;}
Note that it uses a while loop, which will be judged one more time than that of if (flag) {}. The overall idea is to make a comparison before making a modification. If the current value read is the same as the expected value, it will increase itself, otherwise it will continue to poll for modification.
Small summary
Through the above process, we can actually summarize the underlying implementation principle of CAS.
Volatile spin lock unsafe class
Add: CAS, through the underlying implementation of the Native method, is essentially a concurrency primitive of CPU at the operating system level. JVM will directly implement the instructions at the assembly level and rely on hardware to implement. In addition, for CPU primitives, there are two characteristics 1, must be continuous, 2. Uninterrupted
Advantages and disadvantages of CAS
Advantages:
At the bottom of it, we see the spin lock implemented by do-while, which saves the extra overhead of context switching caused by switching between multiple threads.
Disadvantages:
The cost of context switching is saved by constantly trying to get it through the while loop, but the CAS that takes up the resources of cpu can only guarantee the atomicity of one shared variable. If there are multiple shared variables, there is an ABA problem in the implementation.
ABA problem
What is the ABA problem?
If we play like this, we still have two AB threads that assign an initial value of 0 to AtomicInteger.
The code in thread An is as follows:
Thread.sleep (3000); atomicInteger.compareAndSet (0pm 2019)
The code in thread B is as follows:
AtomicInteger.compareAndSet (0penny 1); atomicInteger.compareAndSet (1penny 0)
The AB thread starts at the same time, although the final result is that thread A can change the value to 2019, but it does not perceive that thread B has changed the data during its sleep, in other words, thread A has been deceived by thread B.
The solution to the ABA problem-AtomicStampedRefernce.java
For time-stamped atomic references, the implementation mechanism is through atomic references + version numbers. Each change to the specified value will add 1 to the corresponding version number. Examples are as follows
/ / 0 indicates initialization, and 1 indicates the initial version number AtomicStampedReference reference = new AtomicStampedReference (0,1)
Reference.getStamp ()
/ / get the version number reference.attemptStamp (1meme2)
/ / expectation is 1. If it is 1, update it to 2.
Atomic reference
In JUC, we can find a defined implementation class like AtomicInteger, but JUC does not provide us with atomic reference types of custom types such as AtomicUser or AtomicProduct, but java still provides the back door, that is, atomic reference types.
Examples of use:
User user = getUserById (1)
AtomicReference userAtomicReference = new AtomicReference ()
User.setUsername ("Zhang San")
UserAtomicReference.compareAndSet (user,user)
What are the relevant knowledge and principles of JavaCAS to share here, I hope the above content can be of some help to you, can learn more knowledge. 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.