varhandle是java 9起官方推荐的unsafe安全替代方案,通过jvm原生支持的类型化句柄实现编译期类型校验、内存语义保障与模块化约束,支持实例/静态字段及数组元素的原子操作,性能接近unsafe且规避其崩溃与安全隐患。

用 VarHandle 实现安全又高性能的底层原子操作,核心在于绕过 Unsafe 的隐患,同时保留接近硬件级的效率。它不是语法糖,而是 JVM 原生支持的标准化访问通道——类型在编译/链接期校验、内存语义由 JMM 保障、调用路径受模块系统约束。
创建句柄:权限与类型必须一步到位
VarHandle 不可 new,也不能跨类随意访问字段。关键靠 MethodHandles.lookup() 或更严格的 privateLookupIn() 获取查找器,再匹配字段三要素:所属类、字段名、字段类型(严格区分 int.class 和 Integer.class)。
- 实例字段用
findVarHandle(Owner.class, "fieldName", type.class) - 静态字段必须用
findStaticVarHandle(Owner.class, "fieldName", type.class),传null作为操作对象 - 数组元素用
arrayElementVarHandle(int[].class),后续操作第二个参数是索引,不是偏移量 - 访问 private 字段时,若不在同一模块或未显式开放权限,需用
privateLookupIn(Owner.class, lookup)构造查找器
执行原子操作:方法名即语义,无需手动配内存屏障
VarHandle 把 CAS、读改写、位运算等行为封装成直白的方法名,JVM 自动插入对应内存屏障,不用像 Unsafe 那样自己算顺序或加 volatile。
-
compareAndSet(obj, expected, desired):带 volatile 语义的 CAS,失败返回 false -
getAndAdd(obj, delta):返回旧值,自动保证 acquire-release -
getAndBitwiseOr(obj, mask):仅支持int和long字段,要求字段为private final原始类型 -
setVolatile(obj, value)、setOpaque(obj, value)、setRelease(obj, value):显式控制内存排序强度
为什么比 Unsafe 更稳也更快
Unsafe 的崩溃风险来自运行时偏移错位、类型误用、反射绕过安全检查;而 VarHandle 把这些拦在启动阶段:
- 字段偏移由 JVM 内部绑定,不暴露给用户,杜绝跨 GC 算法或 JVM 实现导致的 offset 错误
- 类型不匹配在
findVarHandle时就抛NoSuchFieldException或IllegalAccessException,不会静默污染内存 - 所有调用走标准 API 流程,能被 JIT 充分内联优化,实测性能接近 Unsafe,远超反射
- JDK 17+ 默认强封装下,Unsafe 反射调用被拦截,VarHandle 仍可正常工作
和 AtomicXXX 类怎么选
AtomicInteger 这类封装适合简单计数场景,开箱即用;VarHandle 更适合需要细粒度控制的场合:
- 要对某个已有类的特定字段做原子更新,不想额外包装一层 AtomicXXX
- 需混合使用不同内存语义(比如部分操作用 opaque,部分用 volatile)
- 要原子操作数组某下标元素,或嵌套对象中的深层字段
- 追求极致性能且愿意承担稍高的 API 使用成本
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











