So I have this code excerpt (a minimal reproduction, from a much larger project, and blocking issue). It leverages Java 22 (preview)'s structured task scope in combo with virtual threads:
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();
}
}
Using Java 22, you can run it with java --enable-preview --source 22 playground.java
.
You are using the structured task scope wrong.
The JavaDoc for StructuredTaskScope.fork()
states:
StructureViolationException
PREVIEW - if the current scoped value bindings are not the same as when the task scope was created
Your code changes the scoped value bindings by calling ScopedValue.runWhere(NAME, "haha", () -> {});
after the task scope was created.
You should probably structure your code like this:
void main() throws InterruptedException {
final var NAME = ScopedValue.<String>newInstance();
ScopedValue.runWhere(NAME, "haha", () -> {
try (var ts = new StructuredTaskScope<>()) {
ts.fork(() -> {
return null;
});
});
ts.join();
}
}
Or you can create a new task scope after changing the scoped value:
void main() throws InterruptedException {
final var NAME = ScopedValue.<String>newInstance();
try (var ts = new StructuredTaskScope<>()) {
ScopedValue.runWhere(NAME, "haha", () -> {
try (var ts2 = new StructuredTaskScope<>()) {
ts2.fork(() -> {
return null;
});
ts2.join();
}
});
ts.join();
}
}