You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

这是Java的Bug还是我误用了Java(预览版)的结构化任务范围?

问题:Java 22结构化任务范围结合ScopedValue触发StructureViolationException

以下是从大型项目中提取的最小复现代码,使用Java 22(预览版)的结构化任务范围与虚拟线程,运行时抛出异常,请问这是Java的Bug还是API误用?

playground.java

void main() throws InterruptedException {
  final var NAME = ScopedValue.<String>newInstance();
  try (var ts = new StructuredTaskScope<>()) {
    ScopedValue.runWhere(NAME, "haha", () -> {
      ts.fork(() -> {
   // ^^^
   // java.util.concurrent.StructureViolationException: Scoped value bindings have changed
        return null;
      });
    });
    ts.join();
  }
}

运行命令:java --enable-preview --source 22 playground.java


解答

这是API误用,不是Java的Bug。核心原因如下:

  • StructuredTaskScope的设计规则:调用fork()方法的线程,其ScopedValue绑定必须与创建该任务范围时的绑定完全一致。
  • 你的代码中,ts是在未绑定NAME的上下文里创建的,但调用ts.fork()时,线程已经通过ScopedValue.runWhere()修改了绑定状态,导致上下文不匹配,触发StructureViolationException。

正确写法示例

方式一:在fork的任务内部绑定ScopedValue

将ScopedValue的绑定逻辑放在fork出的任务中,确保任务继承任务范围的上下文后再修改绑定:

void main() throws InterruptedException {
  final var NAME = ScopedValue.<String>newInstance();
  try (var ts = new StructuredTaskScope<>()) {
    ts.fork(() -> {
      return ScopedValue.runWhere(NAME, "haha", () -> {
        // 在此执行需要使用NAME绑定值的逻辑
        return null;
      });
    });
    ts.join();
  }
}

方式二:先绑定ScopedValue再创建任务范围

如果需要主线程先绑定ScopedValue再管理任务范围,需在绑定上下文内创建StructuredTaskScope:

void main() throws InterruptedException {
  final var NAME = ScopedValue.<String>newInstance();
  ScopedValue.runWhere(NAME, "haha", () -> {
    try (var ts = new StructuredTaskScope<>()) {
      ts.fork(() -> {
        // 此处可直接访问NAME的绑定值"haha"
        return null;
      });
      ts.join();
    }
  });
}

内容的提问来源于stack exchange,提问作者Salathiel Genese

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 10:41:09