【Beautiful JUC Part.6】CAS 不可中断的典范

【Beautiful JUC Part.6】CAS 不可中断的典范

一、什么是CAS

【Beautiful JUC Part.6】CAS 不可中断的典范

运用场合:并发场景,实现不能被打断的交换操作

主要思路:

  • 我认为V的值应该是A,如果是的话那我就把它改成B,如果不是A(说明被别人修改过了),那我就不修改了,避免多人同时修改导致出错。
  • CAS有三个操作数:
    • 内存值V、预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才将内存值修改为B,否则什么都不做。最后返回现在的V值
  • CPU的特殊指令
    • 一个指令可以比较和赋值

二、CAS的等价代码、应用场景

1、演示案例

public class TwoThreadsCompetition implements Runnable{
    private volatile int value;
    public synchronized int compareAndSwap(int expectedValue, int newValue) {
        int oldValue = value;
        if (oldValue == expectedValue) {
            value = newValue;
        }
        return oldValue;
    }

    @Override
    public void run() {
        compareAndSwap(0, 1);
    }

    public static void main(String[] args) throws InterruptedException {
        TwoThreadsCompetition r = new TwoThreadsCompetition();
        r.value = 0;
        Thread t1 = new Thread(r, "线程1");
        Thread t2 = new Thread(r, "线程2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(r.value);
    }
}

模拟CAS操作

2、应用场景

  • 乐观锁
  • 并发容器
    • concurrentHashMap
  • 原子类

3、分析原子类的CAS

AtomicInteger类

【Beautiful JUC Part.6】CAS 不可中断的典范

AtomicInteger加载Unsafe工具,用来直接操作内存数据

用Unsafe来实现底层操作

用volatile修饰value字段,保证可见性

getAndAddInt方法分析

【Beautiful JUC Part.6】CAS 不可中断的典范

Unsafe类

【Beautiful JUC Part.6】CAS 不可中断的典范

总结

【Beautiful JUC Part.6】CAS 不可中断的典范

三、CAS的缺点

1、ABA问题

因为CAS只是做和原值相不相等的检查,并没有检查是否被修改。

假设有三个线程,原值是5,线程2把5改为7,线程3又把7改成5,等到第一个线程查看是否是5,发现真的是5,线程1以为没有任何线程对其进行修改,所以线程1就会把这个5改成所期待的值。但是实际上已经有人修改过了。

2、如何解决

可以添加版本号,比如说第一个版本的5,第二个版本的5

3、自旋时间过长

在原子类的getAndAddInt方法中可以看到,一直在cas部分自旋,如果一直等待锁,就会造成消耗资源的问题。

上一篇:如何初始化centos或debian系统(公司)


下一篇:vue2响应式通过数组下标赋值响应式问题