Java并发的CAS原理与ABA问题的讲解

CAS原理

在计算机科学中,比较和交换(Compare And Swap)是用于实现多线程同步的原子指令。 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。 这是作为单个原子操作完成的。 原子性保证新值基于最新信息计算; 如果该值在同一时间被另一个线程更新,则写入将失败。 操作结果必须说明是否进行替换; 这可以通过一个简单的布尔响应(这个变体通常称为比较和设置),或通过返回从内存位置读取的值来完成(摘自维基本科)

CAS流程

以AtomicInteger.addAndGet()为例讲解CAS

javadoc

public final int addAndGet​(int delta)
Atomically adds the given value to the current value, with memory effects as specified by VarHandle.getAndAdd(java.lang.Object…).
Parameters:
delta - the value to add
Returns:
the updated value

在Java的源码中

public final int addAndGet(int delta) {
  return U.getAndAddInt(this, VALUE, delta) + delta;
}

这里的VALUE是在该类初始化的时候获取到的,理解一下就是这时候我们调用unsafe的objectFieldOffset从Atomic类文件中获取value的偏移量,那么VALUE其实就是记录value的偏移量的。

VALUE准确的是value这个字段相对与AtomicInteger这个对象内存起始地址的偏移量,由于这个方法的最底层是JNI调用native的方法,所以需要传入这个值。

private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");

继续往下执行:

/**
 * Atomically adds the given value to the current value of a field
 * or array element within the given object {@code o}
 * at the given {@code offset}.
 * @param o object/array to update the field/element in
 * @param offset field/element offset
 * @param delta the value to add
 * @return the previous value
 * @since 1.8
 **/
@HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
  int v;
  do {
    v = getIntVolatile(o, offset);
  } while (!weakCompareAndSetInt(o, offset, v, v + delta));
  return v;
}
@HotSpotIntrinsicCandidate
public final boolean weakCompareAndSetInt(Object o, long offset,
                     int expected,
                     int x) {
  return compareAndSetInt(o, offset, expected, x);
}

如果obj内的value和expect相等,就证明没有其他线程改变过这个变量,那么就更新它为update,如果这一步的CAS没有成功,那就采用自旋的方式继续进行CAS操作。从代码中看着也是两个步骤,但其实在JNI里是借助于一个CPU指令完成的,实际还是原子操作。

ABA问题

产生ABA问题的原因

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

如何规避ABA问题

常用的办法是在更新数据的时候加入版本号,以版本号来控制更新。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Java多线程之CAS算法实现线程安全

    前言 对于线程安全,我们有说不尽的话题.大多数保证线程安全的方法是添加各种类型锁,使用各种同步机制,用限制对共享的.可变的类变量并发访问的方式来保证线程安全.文本从另一个角度,使用"比较交换算法"(CompareAndSwap)实现同样的需求.我们实现一个简单的"栈",并逐步重构代码来进行讲解. 本文通俗易懂,不会涉及到过多的底层知识,适合初学者阅读(言外之意是各位大神可以绕道了). 旅程开始 1.先定个小目标,实现一个"栈" "栈&q

  • java使用MulticastSocket实现组播

    组播是一种允许源进程将数据包发送到多个目标进程的网络技术.组播源将数据包发送到特定组播组,只有属于该组播组的进程才能接收到数据包.这些进程可以是在同一个物理网络,也可以来自不同的物理网络(只要有组播路由器支持). 组播分为无连接和面向连接组播,但是基本的组播机制是无连接的,我们这里所讲的也是无连接组播. 我们说过使用MulticastSocket类,这个类叫组播数据报套接字类,主要用来发送和接收IP组播报文.MulticastSocket是DatagramSocket的子类,它增加了加入和离开组

  • 学习非阻塞的同步机制CAS

    在研究线程池的执行原理时,看到一段不断循环重试的代码,不理解它的原理,看注释这是CAS的实现,所以学会之后记录下来. 锁有什么劣势 在多线程并发下,可以通过加锁来保证线程安全性,但多个线程同时请求锁,很多情况下避免不了要借助操作系统,线程挂起和恢复会存在很大的开销,并存在很长时间的中断.一些细粒度的操作,例如同步容器,操作往往只有很少代码量,如果存在锁并且线程激烈地竞争,调度的代价很大. 总结来说,线程持有锁,会让其他需要锁的线程阻塞,产生多种风险和开销.加锁是一种悲观方法,线程总是设想在自己持

  • Java并发的CAS原理与ABA问题的讲解

    CAS原理 在计算机科学中,比较和交换(Compare And Swap)是用于实现多线程同步的原子指令. 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值. 这是作为单个原子操作完成的. 原子性保证新值基于最新信息计算; 如果该值在同一时间被另一个线程更新,则写入将失败. 操作结果必须说明是否进行替换; 这可以通过一个简单的布尔响应(这个变体通常称为比较和设置),或通过返回从内存位置读取的值来完成(摘自维基本科) CAS流程 以AtomicIntege

  • 关于Java 并发的 CAS

    目录 一.为什么要无锁 二.什么是CAS? 三.Java 中的CAS 四.CAS存在的问题 1.自旋的劣势 2.ABA 问题 3.尝试应用 4.CAS 源码 一.为什么要无锁 我们一想到在多线程下保证安全的方式头一个要拎出来的肯定是锁,不管从硬件.操作系统层面都或多或少在使用锁.锁有什么缺点吗?当然有了,不然 JDK 里为什么出现那么多各式各样的锁,就是因为每一种锁都有其优劣势. 使用锁就需要获得锁.释放锁,CPU 需要通过上下文切换和调度管理来进行这个操作,对于一个 「独占锁」 而言一个线程在

  • Java并发CopyOnWrite容器原理解析

    这篇文章主要介绍了Java并发CopyOnWrite容器原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略.从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWri

  • Java并发之CAS原理详解

    目录 开端 1.代码 1.1修改后的代码 1.2代码改进:CAS模仿 2.CAS分析 2.1Java对CAS的支持 2.2CAS实现原理是什么? 2.3CAS存在的问题 2.3.1什么是ABA问题? 2.3.2如何解决ABA问题 总结 开端 在学习源码之前我们先从一个需求开始 需求 我们开发一个网站,需要对访问量进行统计,用户每发送一次请求,访问量+1.如何实现?我们模拟有100个人同时访问,并且每个人对咱们的网站发起10次请求,最后总访问次数应该是1000次 1.代码 package day0

  • Java并发底层实现原理学习心得

    我们知道java实现的并发操作最后肯定是由我们的CPU完成的,中间经历了将java源码编译成.class文件,然后进行加载,然后虚拟机执行引擎进行执行,解释为汇编语言,然后转为操作系统指令,然后转为1,0,最后CPU进行识别执行. 提到java的并发,我们不由的就会想到java中常见的键字:volatile和synchronized,我们接下来就会从这两个关机字展开分析: volatile的底层实现原理 synchronized的实现原理和应用 volatile 说到volatile,在java

  • Java中的CAS和ABA问题说明

    目录 1.CAS 1)CAS概念 2)CAS产生的影响(无锁执行) 3)Automic并发类CAS原理代码分析 4)CAS导致的ABA问题 1.CAS 1)CAS概念 CAS时Compare And Swap缩写,即比较与交换是用于实现多线程同步的原子指令,它将内存位置的内容与给定值相比较,相同则修改内存位置的值为新值,而整个操作是调用的UnSafe的compareAndSwapObject.compareAndSwapInt或者compareAndSwapLong完成的,而这些方法都是nati

  • Java并发编程总结——慎用CAS详解

    一.CAS和synchronized适用场景 1.对于资源竞争较少的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源:而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能. 2.对于资源竞争严重的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized.以java.util.concurrent.atomic包中AtomicInteger类为例,其getAn

  • 深入分析Java并发编程之CAS

    在Java并发编程的世界里,synchronized 和 Lock 是控制多线程并发环境下对共享资源同步访问的两大手段.其中 Lock 是 JDK 层面的锁机制,是轻量级锁,底层使用大量的自旋+CAS操作实现的. 学习并发推荐<Java并发编程的艺术> 那什么是CAS呢?CAS,compare and swap,即比较并交换,什么是比较并交换呢?在Lock锁的理念中,采用的是一种乐观锁的形式,即多线程去修改共享资源时,不是在修改之前就加锁,而是乐观的认为没有别的线程和自己争锁,就是通过CAS的

  • 详解java 中的CAS与ABA

    1. 独占锁: 属于悲观锁,有共享资源,需要加锁时,会以独占锁的方式导致其它需要获取锁才能执行的线程挂起,等待持有锁的钱程释放锁.传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁.Java中synchronized和ReentrantLock等独占锁就是悲观锁的思想. 1.1 乐观锁的操作 多线程并发修改一个值时的实现: public class SimulatedCAS { //加volatile的目的是利用其happens-before原则

  • Java并发编程深入理解之Synchronized的使用及底层原理详解 下

    目录 一.synchronized锁优化 1.自旋锁与自适应自旋 2.锁消除 逃逸分析: 3.锁粗化 二.对象头内存布局 三.synchronized锁的膨胀升级过程 1.偏向锁 2.轻量级锁 3.重量级锁 4.各种锁的优缺点 接着上文<Java并发编程深入理解之Synchronized的使用及底层原理详解 上>继续介绍synchronized 一.synchronized锁优化 高效并发是从JDK 5升级到JDK 6后一项重要的改进项,HotSpot虚拟机开发团队在这个版本上花费了大量的资源

随机推荐