Java并发的CAS原理与ABA问题的讲解
作者:JimmyU1 发布时间:2023-11-25 12:17:21
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问题
常用的办法是在更新数据的时候加入版本号,以版本号来控制更新。
来源:https://blog.csdn.net/u012449363/article/details/86549823


猜你喜欢
- 1. 定时任务实现方式定时任务实现方式:Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerT
- C#获取远程图片,需要Form用户名和密码的Authorization认证using System;using System.Collect
- 实现网页版的在线聊天室的方法有很多,在没有来到HTML5之前,常见的有:定时轮询、长连接+长轮询、基于第三方插件(如FLASH的Socket
- 1. Action/Service/DAO简介:Action是管理业务(Service)调度和管理跳转的。Service是管理具体的功能的。
- start方法和run方法$start()$方法用来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到$cpu$时间片,就
- 效果图如下所示: 1、在Adapter中加入如下代码<pre style="background-color:#2
- WinForm RichTextBox文本动态滚动显示文本方在RichTextBox动态显示一些文本信息时,需要一些设置,显示当前要显示的字
- 本文实例讲述了Android利用BitMap获得图片像素数据的方法。分享给大家供大家参考,具体如下:网上看到的参考是:int[] pixel
- feignclient https接口调用报证书错误问题最近在使用 feignclient 过程中,和第三方通过https 协议交互的时候,
- 本文为大家分享了java画出五子棋游戏棋盘的方法,供大家参考,具体内容如下棋盘模块:画五子棋棋盘:19条横线、19条竖线步骤一:显示棋盘我有
- 前言 用过微信的都知道,微信对话列表滑动删除效果是很不错的,这个效果我们也可以有。思路其实很简单,弄个ListView,然后里面的
- 本文实例为大家分享了java实现录音播放的具体代码,供大家参考,具体内容如下需求:1.实现可以从麦克风进行录音2.可以停止录音3.实现播放录
- Android seekbar控制音量同步更新 作为开发人员来讲,seekbar你一定会碰到,那么怎么自定义seekbar以及s
- 前言这几天看《Java并发编程之美》的时候又遇到了ThradLocal这个类,不得不说,这个类在平时很多场景都遇得到,所以对其进行一个系统性
- 本文实例讲述了Java基于递归和循环两种方式实现未知维度集合的笛卡尔积。分享给大家供大家参考,具体如下:什么是笛卡尔积?在数学中,两个集合X
- Warning:这是《Java 程序员进阶之路》专栏的第 55 篇。回来后小二找到了我,于是我就写下了这篇文章丢给他,并严厉地告诉他:再搞不
- 概述在 NAudio 中, 常用类型有 WaveIn, WaveOut, WaveStream, WaveFileWriter, WaveF
- 前言:在看这个变更之前,我们需要回忆下 Android 12 的一个安全性变更, 即声明了 <intent-filter&g
- 1.数据类型的分类Java的数据类型主要分为两类:基本数据类型、引用数据类型Java中的字符串String属于引用数据类型。因为String
- 本文实例讲述了Android编程调用Camera和相册功能。分享给大家供大家参考,具体如下:xml:<LinearLayout xml