zoukankan      html  css  js  c++  java
  • CAS

    CAS

    一. 简介


    利用锁保证线程安全会造成CPU资源浪费(例如线程调度,线程上下文切换等),考虑到锁带来的开销,引入了无锁算法CAS(Compare And Swpa,比较交换),成为整个JUC体系最核心、最基础理论。

    CAS一定要volatile变量配合,这样才能保证每次拿到的变量是主内存中最新的那个值,否则旧的预期值A对某条线程来说,永远是一个不会变的值A,只要某次CAS操作失败,永远都不可能成功。

    • 官方解释:我认为V的值应该是A,如果是,那么将V的值更新为B,否则不修改并告诉V的实际值是多少。其中:V代表内存值,A代表旧的预期值,B代表新的预期值。
    • CAS的目的在于判断欲修改的值是否被修改过。CAS的过程一旦被打断,就会重新开始。以确保操作的原子性。
    • 因为CAS涉及到线程的重新调度问题,所以需要结合具体的cpu内核架构来涉及,因此Java的CAS底层是依靠C语言实现的。目前市面上,服务器流行的内核架构都是支持CAS。

    二. ABA问题


    • 问题:CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,后来变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。

    • 解决思路:使用版本号。在变量前面追加版本号,每次变量更新的时候把版本号+1,那么A->B->A 就会变成1A->2B->3A。从JDK1.5 开始,JDK的Atomic包里提供了一个类Atomic包里提供了一个AtomicStampedReference来解决ABA问题。

      public boolean compareAndSet(
      	V expectedReference, // 预期引用
      	V newReference, // 更新后的引用
      	int expectedStamp, // 预期标志
      	int newStamp // 更新后的标志
      )
      

      compareAndSet方法的作用首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

    三. 缺陷


    1. 循环时间长,开销大

      CAS不成功则会一直自旋,如果自旋CAS长时间不成功,会给CPU带来非常大的执行开销。

    2. 只能保证一个共享变量的原子操作

      当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁。

      还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

  • 相关阅读:
    MYSQL 神奇的操作insert into test select * from test;
    mysql排序字段为空的排在最后面
    Redis有效时间设置及时间过期处理
    Dom4j 使用简介
    ASP.NET中使用多个runat=server form(转)
    谨以此文献给才毕业25年的朋友(转)
    门户网站
    庄思浩和BEA公司
    是什么限制了我们面向对象(的开发) (转)
    模态窗口和非模态窗口
  • 原文地址:https://www.cnblogs.com/juzhuxiaozhu/p/13295249.html
Copyright © 2011-2022 走看看