当前位置:   article > 正文

CAS原理是什么,适用场景有哪些,有什么优缺点_javacas应用场景

javacas应用场景

什么是cas

1.CAS(Compare And Swap)是一种思想是一种用来实现线程安全的算法,同时也是一组cpu指令。Compare And Swap这一条指令就能完成比较与交换的组合操作,不会被打断,主要运用在并发编程语句,实现那些不能被打断的数据交换操作,从而避免了多线程情况下,出现不可预知的问题

2.思路:我认为V的值应该是A,如果是的话,那我就把它改成B,如果不是A(说明被别人修改过了),那我就不修改了,避免多人同时修改导致出错

3.CAS有三个操作数:内存值V、预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才将内存值修改为B,否则什么都不做。最后返回现在的V值

案例

/**
 * 模拟CAS操作,等价代码
 */
public class TwoThreadsCompetition implements Runnable {
    private volatile int value;

    public synchronized int compareAndSwap(int expectedValue,int newValue){
        int oldValue = value;
        if (expectedValue == oldValue){
            value=newValue;
        }
        return oldValue;
    }

    public static void main(String[] args) throws InterruptedException {
        TwoThreadsCompetition r = new TwoThreadsCompetition();
        r.value=0;
        Thread t1 = new Thread(r,"Thread1");
        Thread t2 = new Thread(r,"Thread2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(r.value);
    }
    @Override
    public void run() {
        compareAndSwap(0,1);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

应用场景

1.乐观锁

2,并发容器,以ConcurrentHashMap为例

3.原子类

分析在java中是如何利用CAS实现原子性操作的

以AtomicInteger为例

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

2.用Unsafe来实现底层操作

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

4.getAndAddInt方法分析

5.Unsafe类

① Unsafe是CAS的核心类。Java无法直接访问底层操作系统,而是通过本地(native)方法来访问。不过尽管如此,JVM还是开了一个后门,JDK中有一个类Unsafe,它提供了硬件级别的原子操作

② valueOffset表示的是变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址获取数据的原值的,这样我们就能通过unSafe来实现CAS了

在java中是如何利用CAS实现原子性操作

① Unsafe类中的CompareAndSwapInt方法

  • 方法中先想办法拿到变量的value在内存中的地址

  • 通过Atomic::cmpxchg实现原子性的比较和替换,其中参数x是即将更新的值,参数e是原内存中的值,至此,最终完成了CAS的全过程

缺点

ABA 问题:

在计算时只是检查值是否相等,并没有检查是否被修改过,利用乐观锁时添加版本号,对比版本号检查。

自旋时间过长:

很长时间的自旋(有些死循环操作),如果在此期间竞争很激烈,锁一直拿不到,消耗CPU资源,对性能消耗很大

解决:

  • 代码层面,破坏掉for死循环,当超过一定时间或者一定次数时,return退出。

  • 使用类似ConcurrentHashMap的方法。当多个线程竞争时,将粒度变小,将一个变量拆分为多个变量,达到多个线程访问多个资源的效果,最后再调用sum把它合起来,能降低CPU消耗,但是治标不治本。

  • 使用JVM能支持处理器提供的pause指令来提升效率。pause指令有两个作用:第一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零;第二,它可以避免在循环的时候因内存顺序冲突(Memory Order Violation)而引起CPU流水线被清空,从而提高CPU的实行效率

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/311440
推荐阅读
相关标签
  

闽ICP备14008679号