bigywater.tech
Java 内部原理 · 71

VarHandle 原子操作真实验证:8线程CAS自增80万次真实无一丢失

VarHandle 是 Java 9 引入的、用来替代 sun.misc.Unsafe 的标准原子操作 API,但很多人只知道它存在,没真的用它写过并发代码。这篇真实用它实现一个多线程安全自增,和 AtomicInteger 对照验证正确性。

CAS 失败真实不修改值
真实验证:compareAndSet(c, 0, 200) 在字段已经是100时,真实返回false,且值真实保持100不变
8线程80万次真实零丢失
真实验证:8个线程各自CAS自增10万次,循环重试直到成功,真实最终值精确等于80万,和AtomicInteger结果一致

上一篇:instanceof 模式匹配真实验证

真实验证:compareAndSet() 和 getAndAdd() 的基础语义

用 MethodHandles.lookup().findVarHandle() 拿到一个字段的 VarHandle,真实验证 CAS 成功和失败两种场景,以及原子读改写操作。

VarHandleDemo.java static final VarHandle VALUE_HANDLE = MethodHandles.lookup().findVarHandle(Counter.class, "value", int.class); Counter.VALUE_HANDLE.compareAndSet(c, 0, 100); // 期望0,真实0 -> 成功 Counter.VALUE_HANDLE.compareAndSet(c, 0, 200); // 期望0,真实100 -> 失败
真实实测
CAS(0->100) 第一次真实成功: true, c.value=100
CAS(0->200) 第二次真实失败(期望值不匹配): false, c.value=100
getAndAdd(50) 真实返回旧值: 100, 之后 c.value=150

真实结果验证了 VarHandle.compareAndSet() 的标准 CAS 语义:只有当字段的当前值真实等于传入的期望值时,才会把它更新为新值并返回 true;期望值不匹配时,真实什么都不做,直接返回 false——这和 AtomicInteger.compareAndSet()、Unsafe.compareAndSwapInt() 的语义完全一致,只是 VarHandle 是标准化的公开 API,不需要像 Unsafe 那样通过反射绕过访问限制才能拿到。

真实验证:多线程 CAS 自旋自增的正确性

经典的无锁自增模式:循环读取当前值、尝试CAS更新,失败就重读重试,真实验证8线程并发下会不会丢更新。

VarHandleDemo.java int cur; do { cur = (int) VALUE_HANDLE.getVolatile(shared); } while (!(boolean) VALUE_HANDLE.compareAndSet(shared, cur, cur + 1));
真实实测
8线程各自CAS自增100000次,真实最终值: 800000 (期望: 800000)
AtomicInteger对照组最终值: 800000
真实证明了什么。8 个线程各自尝试自增 10 万次,总计 80 万次操作,在没有任何 synchronized 或 Lock 的情况下,最终值真实精确等于 80 万,一次更新都没有丢失。这背后的真实机制和 AtomicInteger 完全相同:compareAndSet() 底层依赖 CPU 的原子指令(如 x86 的 CMPXCHG),保证"比较并交换"这个操作本身不可分割,多个线程同时竞争时,只有一个能在某个时刻真实成功,其余的会真实感知到失败并重试,直到自己也成功——这就是无锁并发数据结构的基础原理。AtomicInteger 对照组同样精确等于 80 万,证明 VarHandle 提供了完全等同的正确性保证。

真实结论:什么时候该用 VarHandle 而不是 AtomicInteger

既然正确性一样,VarHandle 的真实价值在哪?它的优势在于不需要把字段包装成 AtomicInteger 这样的专用类型——可以直接对一个普通的 int/long/引用类型字段做原子操作,这在字段本身还需要被其他非原子逻辑读写、或者需要节省对象包装开销(比如高频创建的小对象)的场景下更灵活。它同时也是 JDK 内部实现 java.util.concurrent 包里许多类(替代早期基于 Unsafe 的实现)的标准工具。

分步演示:VarHandle 真实能做到哪些 Atomic 类做不到的事

每一行都是真实运行这段代码得到的结果。

VarHandle 真实用同一套API统一了字段访问、数组元素访问、CAS,以及release/acquire这类过去只能靠Unsafe才能拿到的细粒度内存语义
这一步新验证的VarHandle操作

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,8线程CAS测试重复运行结果均精确等于80万,零丢失。
    • 和LongAdder vs AtomicInteger那篇一起看,能更完整理解 JDK 并发包在不同抽象层级上提供的原子操作工具。
    • 没有涉及:VarHandle 的内存序变体(acquire/release/opaque模式,对应不同强度的可见性保证)、VarHandle 对数组元素和堆外内存的原子操作支持——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号