当前位置: 首页 > news >正文

Java的CAS是如何实现的、ABA问题

CAS的关键实现 

在 Java 中,实现 CAS操作的一个关键类是Unsafe,位于sun.misc包下:

A collection of methods for performing low-level, unsafe operations. 
Although the class and all methods are public, use of this class is limited because only trusted code can obtain instances of it. 
Note: It is the resposibility of the caller to make sure arguments are checked before methods of this class are called. 
While some rudimentary checks are performed on the input, the checks are best effort and when performance is an overriding priority, 
as when methods of this class are optimized by the runtime compiler, some or all checks (if any) may be elided. 
Hence, the caller must not rely on the checks and corresponding exceptions!

该类并不推荐开发者在应用程序中使用,而是用于 JVM 内部或一些需要极高性能和底层访问的库中。

sun.misc.Unsafe类提供了compareAndSwapObjectcompareAndSwapIntcompareAndSwapLong方法来实现的对Objectintlong类型的 CAS 操作,如:

private static final jdk.internal.misc.Unsafe theInternalUnsafe = jdk.internal.misc.Unsafe.getUnsafe();@ForceInlinepublic final boolean compareAndSwapInt(Object o, long offset,int expected,int x) {return theInternalUnsafe.compareAndSetInt(o, offset, expected, x);}
其中theInternalUnsafe是jdk.internal.misc包下Unsafe的实例,它的compareAndSetInt方法则是本地方法,如下:
@HotSpotIntrinsicCandidatepublic final native boolean compareAndSetInt(Object o, long offset,int expected,int x);

Unsafe的具体使用

在juc包的atomic包提供了一些原子操作类,这些atomic类依赖于CAS乐观锁保证原子性,以AtomicInteger核心源码为例:

// 获取 Unsafe 实例
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long valueOffset;static {try {// 获取“value”字段在AtomicInteger类中的内存偏移量valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }
}
// 确保“value”字段的可见性
private volatile int value;// 如果当前值等于预期值,则原子地将值设置为newValue
// 使用 Unsafe#compareAndSwapInt 方法进行CAS操作
public final boolean compareAndSet(int expect, int update) {return U.compareAndSwapInt(this, valueOffset, expect, update);
}// 原子地将当前值加 delta 并返回旧值
public final int getAndAdd(int delta) {return U.getAndAddInt(this, valueOffset, delta);
}// 原子地将当前值加 1 并返回加之前的值(旧值)
// 使用 Unsafe#getAndAddInt 方法进行CAS操作。
public final int getAndIncrement() {return U.getAndAddInt(this, valueOffset, 1);
}// 原子地将当前值减 1 并返回减之前的值(旧值)
public final int getAndDecrement() {return U.getAndAddInt(this, valueOffset, -1);
}

sun.internal.misc.Unsafe类有如下方法: 

// 原子地获取并增加整数值
public final int getAndAddInt(Object o, long offset, int delta) {int v;do {// 以 volatile 方式获取对象 o 在内存偏移量 offset 处的整数值v = getIntVolatile(o, offset);} while (!compareAndSwapInt(o, offset, v, v + delta));// 返回旧值return v;
}

CAS执行流程

  • 线程从主存读取要修改的值存到本地线程缓存中
  • 执行 CAS 操作,将本地线程缓存中的值与主内存中的值进行比较;
  • 如果本地线程缓存中的值与主内存中的值相等,则将需要修改的值在本地线程缓存中修改;
  • 如果修改成功,将修改后的值写入主内存,并返回修改结果;如果失败,则返回当前主内存中的值;
  • 在多线程并发执行的情况下,如果多个线程同时执行 CAS 操作,只有一个线程的 CAS 操作会成功,其他线程的 CAS 操作都会失败,这也是 CAS 的原子性保证。

CAS问题

1.ABA问题

线程读取某变量的时候值为A,再次读取的时候值仍为A,不能说明该变量是否被其他线程改过,解决思路是在变量前面追加上版本号或者时间戳。JDK 1.5 以后的 AtomicStampedReference 类就是用来解决 ABA 问题的,其中的 compareAndSet() 方法就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

2.循环时间长开销大

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

http://www.dtcms.com/a/288232.html

相关文章:

  • 生成式引擎优化(GEO)权威指南:提升网站在AI搜索中的可见性
  • 我们使用 Blender 和 Godot 的工作流程
  • Python高级数据类型:字典(Dictionary)
  • 遇到SolidWorks 安装失败
  • AI辅助编程时代的高效规范开发指南:工具、原则与提效策略
  • Python 桌面版 数独游戏(一版)
  • window上docker安装RabbitMQ
  • Synopsys Datapath Coding 指南
  • 【ExtendScript Toolkit CC】【PR插件开发】获取当前序列的所有剪辑片段名
  • 技术文章:PCB基板的介电强度
  • RT-Thread的概念和移植
  • 141. 环形链表
  • 智慧资产管理系统需求文档
  • Java从入门到精通!第九天, 重点!(集合(一))
  • 机器视觉为触摸屏装上“智慧之眼”,打造智能化生产!
  • 仓库源MySQL安装教程
  • aosp15上SurfaceFlinger的dump部分新特性-无Layer相关详细信息输出如何解决?
  • 【Keil5-map文件】
  • 初入了解渗透
  • 【SVM smote】MAP - Charting Student Math Misunderstandings
  • P1816 忠诚 题解
  • leetcode_53 最大子数组和
  • MySQL(145)如何升级MySQL版本?
  • 研华PCI-1285/1285E 系列------(一概述)
  • VIT速览
  • 用 Numpy 手动实现矩阵卷积运算
  • 汽车ECU控制器通信架构
  • 车载诊断架构 --- 故障码DTC严重等级定义
  • LVS部署模式NAT集群案例
  • WSL在 Windows 上使用 Linux 工具链和开发环境