Runnable demos for the ankurm.com structured-concurrency-java article: the ExecutorService thread leak and its fix, every built-in Joiner, structure violations, timeouts, a custom Joiner, JSON thread dumps (in-process and jcmd), scoped values, javap diffs of the API on 25, 26, 27 and 28-ea, compiler output for six pieces of 25/26-era code, and the preview class-file trap between 27 and 28. Transcripts in output/. Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01CifR2BE7PBvRy5hT8TS9oz
structured-concurrency-final — Structured Concurrency, final in JDK 28 (JEP 543)
Companion code for the ankurm.com article Structured Concurrency Is Final in JDK 28 (JEP 543): From Preview to Production (https://ankurm.com/structured-concurrency-java/). The explanation lives in the article, in collapsible sections; this folder holds the runnable sources and the transcripts they produced.
JDK25=/path/to/jdk-25 JDK26=/path/to/jdk-26 JDK27=/path/to/jdk-27 JDK28=/path/to/jdk-28 ./run.sh # regenerates output/*.txt
What was tested against
| Thing | Build | Note |
|---|---|---|
| JDK 28 | Temurin 28-beta+21-ea (28-ea+21, build of 2026-10-22) |
early access; JEP 543 status "Integrated", GA proposed 2027-03-09. No flags needed |
| JDK 27 | Temurin 27.0.1.0.2+1 | GA 2026-09-15. Seventh preview (JEP 533): needs --enable-preview |
| JDK 26 | Temurin 26.0.2.1+1 | sixth preview (JEP 525), for the old-API compile results |
| JDK 25 | Temurin 25.0.5+8 | fifth preview (JEP 505), for the API diffs |
javap prints identical StructuredTaskScope signatures on 27 and on 28-ea+21 (output/09-api-diff.txt). Nothing here was run on a GA JDK 28, because none exists yet.
Layout
src/— runnable demos, no flags on JDK 28:Server(the canonical program),UnstructuredandFailFast(the thread leak and its fix),Joiners(the built-in joiners),Failures(structure violations and failure handling),Timeouts,CollectingJoiner(a custom joiner),RandomTasks(seeded),StuckClose(a subtask that ignores interrupts),ThreadDump(JSON thread dump with the scope hierarchy),ScopedValues,SnippetsandQuickReference(the short fragments quoted in the article).broken/— six sources that compile on JDK 26 and fail on 28:MissingCatch,OldFailedException,OldTimeoutException,AwaitAll,OldJoiner,ShutdownOnFailure.output/— one transcript per script step;run.shregenerates all of them.
| Transcript | What it shows |
|---|---|
01-server.txt |
the canonical program on 28 (no flags), on 27 (--enable-preview), and the 27 compile errors without the flag |
02-unstructured-vs-structured.txt |
ExecutorService leaks the sibling; StructuredTaskScope interrupts it |
03-joiners.txt |
allSuccessfulOrThrow, anySuccessfulOrThrow, awaitAllSuccessfulOrThrow, allUntil, the Function overloads |
04-failures.txt |
get() before join(), no join(), non-owner fork, out-of-order close, join twice, cause pattern matching |
05-timeouts-and-custom-joiner.txt |
scope timeouts, a partial-result timeout(), thread factory, a custom joiner |
06-thread-dump.txt, 15-jcmd-thread-dump.txt |
the scope as a container in a JSON thread dump (in-process and via jcmd) |
07-scoped-values.txt |
subtasks inherit a ScopedValue binding, a plain thread does not |
08-api-28.txt, 09-api-diff.txt |
javap of the API on 28, and the diffs 25 to 26 to 27 to 28 |
10-broken-old-api.txt |
the compiler's messages for 25/26-era code on 28 |
11-preview-traps.txt |
a class compiled with preview on 27 does not load on 28; --release 27 on a 28 compiler |
12-snippets.txt |
the short fragments in the article compile and run |
13-random-tasks.txt, 14-stuck-close.txt |
seeded fan-out with one slow task; a subtask that ignores interrupts |
Everything is byte-stable between runs (timings are reduced to booleans). The JEP statements (what changed in each preview) come from the JEP texts on openjdk.org; only the 25 to 28 API differences were checked against binaries.