Java17使用@jdk.internal.vm.annotation.Contended报错如何解决
问题现象
在Java 17环境下使用@jdk.internal.vm.annotation.Contended注解开发伪共享测试代码时,两个主流IDE均出现报错:
- Eclipse 提示:
The type jdk.internal.vm.annotation.Contended is not accessible,运行时抛出编译异常:
Exception in thread "main" java.lang.Error: Unresolved compilation problem: jdk.internal.vm.annotation cannot be resolved to a type at falseSharingExample.ContendedExample1.<init>(ContendedExample1.java:5) at falseSharingExample.FalseSharingMain.main(FalseSharingMain.java:7)
- IntelliJ IDEA 编译时提示:
java: exporting a package from system module java.base is not allowed with --release
相关报错截图:
测试代码如下:
public class ContendedExample1 { @jdk.internal.vm.annotation.Contended public volatile long count1 = 0; public volatile long count2 = 0; } public class FalseSharingMain { public static void main(String[] args) { ContendedExample1 obj1 = new ContendedExample1(); long iteration = 1_000_000_000; new Thread(() -> { long sTime = System.currentTimeMillis(); for(long i = 0; i < iteration; i++) { obj1.count1++; } long eTime = System.currentTimeMillis(); System.out.println(eTime - sTime); }).start(); new Thread(() -> { long sTime = System.currentTimeMillis(); for(long i = 0; i < iteration; i++) { obj1.count2++; } long eTime = System.currentTimeMillis(); System.out.println(eTime - sTime); }).start(); } }
问题原因
jdk.internal.vm.annotation.Contended是JDK内部专用注解,不属于公开支持的API范畴。从Java 9引入模块化系统后,该注解所在的jdk.internal.vm.annotation包被java.base模块封装,默认不对外开放访问权限。同时IDE默认启用的--release编译参数会严格校验模块访问规则,禁止应用代码直接引用系统模块的内部包。
另外需要注意:即使编译通过,JVM默认会限制@Contended注解的生效,需要额外添加参数开启注解处理,否则注解不会起到缓存行隔离的作用。
解决方法
方案1:配置IDE和JVM参数,允许使用内部注解
Eclipse 配置步骤
- 右键项目选择「Properties」,进入「Java Build Path > Libraries」标签页
- 展开当前绑定的JRE 17节点,双击「Access rules」选项
- 点击「Add」,规则类型选择「Accessible」,规则模式填写
jdk/internal/vm/annotation/**,保存规则配置 - 进入「Java Compiler」配置页,取消勾选「Use '--release' option from compiler compliance」选项,关闭--release编译校验
- 打开主类的运行配置,在VM arguments栏添加以下参数:
--add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED -XX:-RestrictContended
IntelliJ IDEA 配置步骤
- 进入「File > Settings > Build, Execution, Deployment > Compiler > Java Compiler」配置页
- 在「Additional command line parameters」输入框中添加:
--add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED - 进入「Project Structure > Project」配置页,将Project SDK、Project language level直接设置为Java 17,不要通过
--release参数指定版本,避免触发模块导出限制 - 打开主类的运行配置,在VM options栏添加以下参数:
--add-exports java.base/jdk.internal.vm.annotation=ALL-UNNAMED -XX:-RestrictContended
方案2(推荐):手动实现缓存行填充,不依赖内部API
@Contended注解的核心作用是给标注的字段前后添加填充字节,避免同一缓存行被多个核心同时读写导致伪共享。可以直接手动在字段前后添加long类型占位变量实现相同效果,不需要修改任何编译、运行参数,兼容性更强:
public class ContendedExample1 { // 前置填充:7个long共56字节,加上对象头8字节刚好凑满64字节缓存行 protected long p1, p2, p3, p4, p5, p6, p7; public volatile long count1 = 0; // 后置填充:7个long共56字节,隔离后续字段 protected long p9, p10, p11, p12, p13, p14, p15; public volatile long count2 = 0; }
内容的提问来源于stack exchange,提问作者Kavishka Madhushan
相关产品推荐
相关产品推荐

