Understanding Understanding CAS and Volatile

Understanding of CAS

What is CAS

CompareAndSweep compares and swaps.

AtomicInteger atomicInteger = new AtomicInteger(1);
//期望值是1,如果达到,那么就更新为2,否则不更新
atomicInteger.compareAndSet(1,2);

spin lock

insert image description here
Compare the value in the working memory of the current thread with the value in the main memory, if the value is expected, then perform the operation, otherwise keep looping
Disadvantages:

  • The cycle will take time.
  • Only one shared variable is guaranteed to be atomic at a time.
  • There is an ABA problem.

ABA problem

There may be ABA problems ahead, what are ABA problems?
Simply put, when thread A is operating a certain value, thread B changes the value in main memory to a certain value and restores it. Thread A does not know that this value has been modified by someone.

How to solve?

By atomic reference
is a class with a version number, similar to the optimistic locking of the database.

//这里设置值的时候传一个版本号
AtomicStampedReference<Integer> asr= new AtomicStampedReference<>(1,1);
//这里操作这个值的时候就将版本号加1,返回值为true则说明这个值未被别的线程修改过,false反之。
asr.compareAndSet(1,2, asr.getStamp(),asr.getStamp()+1);

Volatile

Volatile is a lightweight synchronization mechanism provided by the java virtual machine
1. Guarantees visibility
2. Does not guarantee atomicity
3. Prohibits instruction rearrangement

Visibility experience

public class JMMDemo {
    
    
    //保证可见性,如果不加,线程1会死循环
    private volatile static int num = 0;

    public static void main(String[] args) {
    
    
        new Thread(()->{
    
     //线程1
            int count = 0;
            while(num == 0){
    
    
            }
        },"A").start();

        try {
    
    
            TimeUnit.SECONDS.sleep(1);
        } catch(Exception e){
    
    
            e.printStackTrace();
        }
        num = 1;
        System.out.println(Thread.currentThread().getName()+num);
    }
}

atomic experience is not guaranteed

//不保证原子性
public class VDemo02 {
    
    
    private volatile static int num = 0;
    public static void add(){
    
    
        num++;//不是一个原子性操作
    }
    public static void main(String[] args) {
    
    
        //理论num结果应该为2万
        for (int i = 1; i <= 20; i++) {
    
    
              new Thread(() ->{
    
    
                  for(int j = 0; j < 1000; j++){
    
    
                      add();
                  }
              },String.valueOf(i)).start();
        }
        while(Thread.activeCount() > 2){
    
    
            Thread.yield();
        }
		System.out.println(Thread.currentThread().getName() + " " + num);
    }
}
  • The above operation, num++ is not an atomic operation, and multiple threads operate together in this way, which will cause the value of num to not be the expected value of 20000 .
  • To solve this problem, you can use the atomic class, that is, the AtomicInteger used above, to modify num.

Disable instruction rearrangement

The programs we write, the computers don't execute as we write them.
Source code --> Compiler-optimized rearrangement --> instruction parallelism may also be rearranged --> memory system will also be rearranged --> execution
processor performs instruction rearrangement, taking into account the dependencies between data.

When a variable modified by Volatile is written, a memory barrier will be generated to ensure the execution order of the operation and the instructions will not be rearranged.

Guess you like

Origin blog.csdn.net/qq_41570752/article/details/108521900