Serie de concurrencia de Java: explicación detallada de CAS

Serie de concurrencia de Java: explicación detallada de CAS

CAS

¿Qué es CAS?

CAS significa intercambio de comparación, que es una instrucción atómica de la CPU. CAS implementa un bloqueo optimista que es diferente de los bloqueos de sincronización sincronizados (sincronizar es una idea de bloqueo pesimista, una especie de bloqueo de exclusión mutua, y tomaré el recurso cuando lo obtenga. En mi mano, espere a que libere a los demás, y CAS es un mecanismo de reintento, y si falla, intente nuevamente), cuando varios subprocesos intentan usar CAS para cambiar una variable, solo un subproceso puede actualizar el valor de la variable , y todos los demás subprocesos fallan, el subproceso fallido no se suspende, se le dice que la carrera ha fallado y vuelve a intentarlo. Si bien la comparación y el intercambio son dos acciones, CAS garantiza la atomicidad de comparación e intercambio a nivel de hardware. De hecho, CAS también tiene una operación de bloqueo, pero este bloqueo lo realiza la CPU. La forma de bloqueo del bus garantiza la operación atómica entre multiprocesamiento. . Comparado con Synchronise, el efecto de objeto más monitor es mucho mejor.

Piense en el modelo de memoria Java aquí. Las variables compartidas se almacenan en la memoria principal, y la memoria de trabajo de cada subproceso guarda una copia. El valor esperado en CAS es en realidad una copia de la variable. Cuando un subproceso obtiene una variable de la memoria principal, el valor en la memoria principal puede ser actualizado por otros subprocesos. En este momento, el valor guardado en el subproceso es inconsistente con el valor en la memoria principal y falla. Después de la falla, el valor se vuelve a leer de la memoria principal Funcionamiento en bucle.

Ejemplo de uso

La serie de clases AutomicXXX son los mejores ejemplos de uso. Veamos cómo AutomicInter garantiza la seguridad de los datos sin bloqueos.

   public static void main(String[] args) {
        AtomicInteger atomicInteger=new AtomicInteger(8);
        //当前值为8,期望值为8,改成10 成功  输出true
        System.out.println(atomicInteger.compareAndSet(8,10)+"目前的值为"+atomicInteger.get());
        //当前值为10,期望值为8 改成20 失败 输出false
        System.out.println(atomicInteger.compareAndSet(8,20)+"目前的值"+atomicInteger.get());
   }
复制代码

Echemos un vistazo a la capa inferior de compareAndSet

  public final boolean compareAndSet(int expect, int update) {
        //本地方法,调用CAS源语实现,CPU指令保证原子性,一直等待取到的值
        /**
        * 1:this代表的是unsafe这个类
        * 2:valueOffset:偏移量 valueoffset偏移量(从哪里来看下面的类说明),其实取到的就是目标值
        * 3:expect:期望的值
        * 4:update:更新的值
        *整句话实现的语意是如果this内的value(偏移量得到)和expect相等,就证明没有其他线程改变过这个变量,那么就更新它为update,				 
        * 没有成功的话没就采用自旋的方式继续进行CAS操作(感兴趣的小伙伴可以查看Hotspot源码具体试下过程,公众号程序员fly后面会出相			
        *文章,感兴趣的小伙伴可以关注下微信公众号)。
        **/
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

	/**
	*AtomicInteger类定义的变量和静态块
	*
	**/
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
           //valueOffset其实就是记录value的偏移量的
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

复制代码

problema CAS

CAS es un bloqueo giratorio, que tiene los siguientes problemas

problema ABA

CAS在操作值的时候,会检查值有没有变化,比如原来有一个值是A,然后变成B,之后又变成了A,使用CAS技术进行检查的时候会发现值并没有发生变化,但实际其实是发生了变化的,这就是著名的CAS的ABA问题。常规的解决思路其实是加版本号每次变化的时候将版本号+1。整体变化过程就变成了1A-2B-3A。JDK在1.5之后的AtomicStampedReference就实现了这种实现来解决ABA问题。(AtomicMarkableReference也能解决ABA问题,它是通过一个boolean标记来标识是否有修改,不再是版本号,思想上其实都类似)

循环开销问题

自旋CAS如果长时间不成功的话,会给CPU带来很多开销。

保证一个共享变量原子操作

当对一个共享遍历操作的时候,我们可以循环使用CAS来保证原子操作,但是对多个共享遍历进行操作的时候,循环CAS无法保证原子性,但是有一个取巧的方法就是:多个共享变量合成一个变量进行操作,读过线程池源码同学的都知道,线程池中线程的数量以及线程的状态会合并成一个共享变量操作(线程池源码文章请关注公众号程序员fly了解相关详情)。

闲谈

感觉有帮助的同学还请点赞关注,这将对我是很大的鼓励~,公众号有自己开始总结的一系列文章,需要的小伙伴还请关注下个人公众号程序员fly呀,干货多多,湿货也不少(∩_∩)。

巨人肩膀

www.modb.pro/db/127003

juejin.cn/post/684490…

Supongo que te gusta

Origin juejin.im/post/7030002149362761758
Recomendado
Clasificación