原子性 - CAS 与 Unsafe

本贴最后更新于 2080 天前,其中的信息可能已经东海扬尘

CAS

Compare And Swap(比较并交换),涉及并发算法时常用到的一种技术。 java.util.concurrent.atomic 包下的原子操作类都是基于 CAS 实现的。

现在市面上的处理器基本都支持 CAS,只不过不同的厂家的实现不一样。
CAS 有三个操作数:内存值 V、旧的预期值 A、要修改的值 B,当且仅当预期值 A 和内存值 V 相同时,将内存值修改为 B 并返回 true,否则什么都不做并返回 false

Java 中的 sun.misc.Unsafe 提供了 CAS 机制

Unsafe

Java 无法直接访问底层操作系统,只能通过本地(native)方法来访问。不过尽管如此,JVM 还是开了一个后门,JDK 中有一个类 Unsafe,它提供了硬件级别的原子操作。比如说获取某个属性在内存中的位置,修改对象的字段值。

但是 并没有办法 直接使用它们,JDK API 文档也没有提供任何关于这个类的方法的解释。对于 Unsafe 类的使用是受限制的。

那么我们怎么样来使用呢?

示例代码

import java.lang.reflect.Field; import sun.misc.Unsafe; /** * 使用CAS方式进行i++ * @author ldan * */ public class CounterUnsafe { int i = 0; //Unsafe工具非常强大 ,可以去修改应用类型的值,可以修改对象的属性,可以修改数组 等等 private static Unsafe unsafe = null; //代表了要修改的字段 是一个偏移量 private static long valueOffset; static{ //官方不建议直接使用 //unsafe = Unsafe.getUnsafe(); //利用反射原理进行使用 try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); //指定要修改的字段 Field iField = CounterUnsafe.class.getDeclaredField("i"); valueOffset = unsafe.objectFieldOffset(iField); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } void add(){ //i++不是原子性的 //i++; //原子性的i++ while (true){//只有操作成功才return if(unsafe.compareAndSwapInt(this, valueOffset, i, i+1)) return; } } public static void main(String[] args) { } }

CAS 存在的问题

  1. 仅针对单个变量的操作,不能用于多个变量来实现原子操作。
  2. CAS 自旋的实现,可能让所有线程都出于高频运行,争抢 CPU 执行时间的状态。如果操作长时间不成功,会带来很大的 CPU 资源消耗。
  3. ABA 问题。(无法体现出数据的变动)
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3194 引用 • 8214 回帖
  • CAS
    13 引用 • 21 回帖
  • Unsafe
    1 引用 • 1 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • danl
    作者

    i++