Analysis of CAS principle in Java (analysis of volatile and synchronized)

What is CAS?


The English interpretation of CAS is comparison and exchange. It is the source language at the bottom of the cpu. It is a solution to the atomicity of shared variables. It defines three variables. The memory address value corresponds to V, the expected value E and the value U to be modified, as shown in the following figure. Shows that these variables are in the cache. If two threads A and B modify the shared variables at the same time through cas respectively, assuming that the A thread first obtains the time slice, if the value of V and E are found to be equal, the main memory value will be changed. Update to U. If it is not equal, it means that thread B has been successfully updated before thread A is updated. Thread A will fail and retry. At this time, according to the cache coherency protocol, the local copy of thread A will become invalid and need to be resynchronized from the main memory. The variable to the local memory copy, in Java by calling UnSafe's compareAndSet similar way to call, the bottom layer is c, after decompilation, the operating system instructions are cmpxchg instructions.

image.png

 

Ensure i++ atomicity


You must have a question. Why does the volatile- modified variable i and i++ have thread safety issues, that is, the issue of atomicity. Let's take a step-by-step analysis of a classic i++ case! We know that in the case of multithreading, volatile guarantees the visibility of shared variables and the order of rows, but it cannot guarantee atomicity. The reason is that i++ is a compound operation, which can be roughly divided into 3 steps. 1. Get the latest from the main memory first. The value of i, 2. Save the operation of adding 1 to the operand stack, 3. Take the value of i plus 1 from the stack and write it back to the main memory. OK, when thread AB performs i++ operations at the same time, for example, thread A obtains the time slice first, and executes the second step. This is thread A has not finished executing, the time slice is allocated to thread B, and B executes all operations successfully and synchronizes In addition to the main memory, assuming that the initial value of our i is 1, then the main memory value is 2 at this time, because thread B is executed, the cpu time slice is returned to thread A, and the third operation is performed. At this time, it is synchronized to the main The value of the memory is still 2. Look, threads A and B each perform an operation of adding 1, but the final result may be 2, and the role of cas is here. It can guarantee the atomicity of i++ operations. Why can it guarantee atomicity? ? cas can combine the above three operations into one operation, which is atomic.

 

what is the benefit?


Everyone knows that locks are needed to solve multi-thread safety. Synchronized can be used to solve them. However, synchronized also has its disadvantages. The most important thing is that it is blocking. What are the problems with blocking? Performance, this is something that computer people can't bear. Frequent kernel and outer core switching will seriously waste system resources. So the concept of optimistic lock of cas is mentioned. It is non-blocking, and the operating system does not need to switch back and forth between kernel mode and user mode. It is equivalent to acquiring a lock in a while loop, which has a certain improvement in performance. Even so, there will be certain problems, let's take a look below.

 

What is the problem?


1. The ABA problem.

This case is relatively simple. Thread A changes the shared variable i from 1 to 2 and then to 1, and thread B wants to change i to 2. It should not be successful because the instant variable i is now 1, but its The state has changed, and his solution is the version number. It is equivalent to a successful modification once the version number is increased by 1, and it can be solved. An interviewer once asked a question, is cas thread-safe? The answer is not thread-safe.

2. The spin time is too long.

If a thread has not released the lock after obtaining the lock, other threads can only wait in a loop.

3. Only the atomicity of a shared variable can be guaranteed.

Basically, the Automic package can only guarantee the atomicity of a variable.

 

Use under the JUC package!


Some children's shoes may be more entangled when looking at the JDK source code. They find that the volatile keyword is generally used in conjunction with cas. What if volatile is not used ? Cas itself only acts on methods. Cas has no constraints on shared variables. If shared variables are not volatile modified, they are invisible and cannot guarantee the effectiveness of shared variables. You need to wait for shared variables to be actively synchronized to main memory. This is a costly In terms of time, the efficiency is lower. All the volatile keywords that have been seen in the JUC concurrent package are generally combined with cas .

 

to sum up


This article, we first leads cas concept and explains its advantages and disadvantages, made a presentation case, a simple synchronized keyword and do a comparison, the last in-depth description of the volatile keyword and cas conjunction of efficiency, this This is the conclusion I got after deep thinking. I will share it with you. I hope you like it. Like it!

I'm called Lian, and I'm calling while practicing. Likes and comments are welcome.

Guess you like

Origin blog.csdn.net/duyabc/article/details/111174322