Understanding of CAS mechanism (2)

1. The underlying implementation of CAS in Java
First look at the source code of AtomicInteger, the incrementAndGet method commonly used in AtomicInteger:

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}
private volatile int value;
public final int get() {
    return value;
}

This code is an infinite loop, which is the spin of the CAS. The loop body does three things:
1. Get the current value.
2. The current value + 1, and the target value is calculated.
3. Carry out CAS operation, if successful, jump out of the loop, if failed, repeat the above steps.

The key point to note here is the get method, which is used to get the current value of the variable.
How to ensure that the current value obtained is the latest value in memory? Use the volatile keyword to guarantee.

Let's see how the compareAndSet method guarantees atomic operations.
The implementation of the compareAndSet method:

The implementation of the compareAndSet method is very simple, only one line of code. Two important objects are involved here, one is unsafe and the other is valueOffset.

What is unsafe? Unlike C and C++, the Java language can directly access the underlying operating system, but the JVM provides us with a backdoor, which is unsafe. unsafe provides us with hardware-level atomic operations.

As for the valueOffset object, it is obtained through the unsafe.objectFieldOffset method, which represents the offset of the value member variable of the AtomicInteger object in memory. We can simply understand valueOffset as the memory address of the value variable.

As mentioned in the previous article, 3 basic operands are used in the CAS mechanism: the memory address V, the old expected value A, and the new value B to be modified.

The parameters of the unsafe compareAndSwapInt method include these three basic elements: the valueOffset parameter represents V, the expect parameter represents A, and the update parameter represents B.

It is the unsafe compareAndSwapInt method that guarantees the atomic operation between the Compare and Swap operations.

2. The ABA problem of CAS and its solution The
so-called ABA problem is that the value of a variable is changed from A to B, and then from B to A.
1. Suppose there is a variable with value A in memory, stored at address V.

2. At this time, three threads want to use CAS to update the value of this variable, and the execution time of each thread has a slight deviation. Thread 1 and thread 2 have obtained the current value, thread 3 has not yet obtained the current value.

3. Next, thread 1 executes successfully first, and successfully updates the current value from A to B; at the same time, thread 2 is blocked for some reason and does not perform the update operation; thread 3 obtains the current value after thread 1 is updated. B.

4. After that, thread 2 is still blocked, and thread 3 continues to execute, successfully updating the current value from B to A.

5. Finally, thread 2 finally resumes the running state. Since the "current value" A has been obtained before blocking, and after the compare detection, the actual value in the memory address V is also A, so the variable value A is successfully updated to B.

During this process, the variable value A obtained by thread 2 is an old value. Although it is the same as the current actual value, the variable in the memory address V has undergone the change of A->B->A.
This example seems to be fine on the surface, because it was originally intended to update A to B. The following is an example of an ATM machine based on the actual application scenario:
1. Suppose there is an ATM machine that follows the CAS principle, Xiaohui has a deposit of 100 yuan, and uses this ATM to withdraw 50 yuan.

2. Due to a small problem with the ATM hardware, Xiaohui's withdrawal operation was submitted twice at the same time, and two threads were opened. Both threads obtained the current value of 100 yuan and needed to update it to 50 yuan.
(Ideally, one thread should be updated successfully, the other thread should fail to update, and Xiaohui's deposit should be deducted only once.)

3. Thread 1 executes successfully first and changes the balance from 100 to 50. Thread 2 is blocked for some reason. At this time, Xiaohui's mother just remitted 50 yuan to Xiaohui.

4. Thread 2 is still blocked, thread 3 is executed successfully, and the balance is changed from 50 to 100.

5. Thread 2 resumes operation. Since the "current value" of 100 has been obtained before blocking, and after the compare test, the actual value of the deposit is also 100 at this time, so the variable value of 100 is successfully updated to 50.

Originally, thread 2 should have failed to submit, and the correct balance of Xiaohui should be kept at 100 yuan. As a result, the submission was successful due to the ABA problem.
The solution to the ABA problem: add a version number. To really achieve a rigorous CAS mechanism, we must not only compare the expected value A with the actual value in the address V in the Compare phase, but also compare whether the version numbers of the variables are consistent.
Still explain the chestnut in the previous article,
1. Suppose that the variable value A is stored in the address V, and the current version number is 01. Thread 1 gets the current value A and version number 01, and wants to update to B, but is blocked.

2. At this time, the variable in the memory address V has changed many times, and the version number is increased to 03, but the variable value is still A.

3. Then thread 1 resumes running and performs the Compare operation. After comparison, the value obtained by thread 1 and the actual value of address V are both A, but the version numbers are not equal, so this update fails.

In Java, the AtomicStampedReference class implements the CAS mechanism that uses version numbers for comparison.
Review
1. How is the bottom layer of the Java language CAS implemented?
Using unsafe provides atomic operation methods.

2. What is an ABA problem? How to deal with it?
When a value is updated from A to B, and then updated to A, the common CAS mechanism will misjudge and pass the test.
Using version number comparison can effectively solve the ABA problem.

Reference: Comic: What is the CAS mechanism? (Advanced)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325090471&siteId=291194637