How much do you know about CAS, a must-ask question in an interview?

Preface

Java's latest interview questions (java basics, collections, multi-threading, jvm, locks, algorithms, CAS, Redis, database, mybatis, spring, springMVC, springBoot, microservices)

1. What is CAS?

CAS (Compare And Swap): Compare and replace, a lock-free algorithm. Achieve variable synchronization between multiple threads without using locks.

V: value in main memory
E: expected value
N: new value

2. CAS implementation process

Note:
① When a thread is started, a copy of the variables will be copied from the main memory to each thread's respective running environment.
② The failed thread will not be suspended, but will be informed that it failed in this competition and can try again.

Concurrent environment: perform +1 operation, the initial value of main memory V is 0, and there are two threads T1 and T2. The respective copy variables V1 and V2 are 0. Assume that T1 gets the execution right first.

The first step: T1 reads the current value of V1 and assigns it to E1.
Insert image description here

Step 2: T1 performs +1 operation, N1 = E1 + 1.
Insert image description here

Step 3: Compare E1 with main memory V and find that E1 = V.
Insert image description here

Step 4: Write N1 into the main memory, and the main memory V becomes 1.
Insert image description here

Step 5: T2 gets the execution right, T2 reads the current value of V2 and assigns it to E2 (V2 is still 0 at this time).

Insert image description here
Step 6: T2 performs +1 operation, N2 = E2 + 1.
Insert image description here

Step 7: Compare E2 with main memory V and find that E2 != V.
Insert image description here

Step 8: Reacquire the value of the main memory, V = 1, assign it to V2, and assign V2 to E2.
Insert image description here

Step 9: T2 performs +1 operation, N2 = E2 + 1.
Insert image description here

Step 10: Compare E2 with main memory V and find that E2 = V.
Insert image description here
Step 11: Write N2 into the main memory, and the main memory V becomes 2. mission accomplished.
Insert image description here

3. Disadvantages of CAS

1. Long cycle time

If many threads try to modify a value, they will keep trying without success.

2. Only a shared variable can be guaranteed to be an atomic operation

3.ABA problems and solutions

Reason: The operation variable of thread 1 is changed to A, the thread hangs, and then the operation variable of thread 2 is changed to X, then to Z, and finally to A. In fact, the value of the intermediate variable has been changed.
Solution:
① Use the AtomicStampReference class and add a marker stamp to determine whether the data has been modified.

public class AtomicStampedReference<V> {
    
    

    private static class Pair<T> {
    
    
        final T reference;
        final int stamp;
        private Pair(T reference, int stamp) {
    
    
            this.reference = reference;
            this.stamp = stamp;
        }
        static <T> Pair<T> of(T reference, int stamp) {
    
    
            return new Pair<T>(reference, stamp);
        }
    }

② You can use the version number, which is actually similar to the stamp principle above.

4. Expansion questions

1.Are i++ and ++i atomic operations?

Not an atomic operation. Not a separate instruction. It's three instructions

Step 1: Get this value
Step 2: +1
Step 3: Write back this value

2. How can i++ ensure atomicity without adding lock and synchronized?

There is an AtomicInteger class inside the Atomic class (the bottom layer is CAS).

	//提供了硬件级别的原子操作,方法都是 native 修饰
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    public final boolean compareAndSet(int expect, int update) {
    
    
         //valueOffset=V,E=expect,N=update
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }


	实例:
	public static void main(String[] args) {
    
    
        //初始值是0,源码里面有注释
        AtomicInteger a1 = new AtomicInteger();

        //初始值是250
        AtomicInteger a2 = new AtomicInteger(250);

        //以原子方式将当前值递增1并在递增后返回新值。它相当于i++操作。
        int i1 = a1.incrementAndGet();
        System.out.println(i1); // 1
        
        //以原子方式递增当前值并返回旧值。它相当于++i操作。
        int i2 = a2.getAndIncrement();
        System.out.println(i2); // 250
    }

Guess you like

Origin blog.csdn.net/twotwo22222/article/details/128944814