import com.sun.management.HotSpotDiagnosticMXBean; import java.lang.management.ManagementFactory; import java.nio.file.*; import java.util.concurrent.*; import java.util.concurrent.StructuredTaskScope.Joiner; /** The thread dump shows the scope as a container, its owner, and the threads forked in it. */ public class ThreadDump { public static void main(String[] args) throws Exception { if (args.length > 0 && args[0].equals("hold")) { // used by run.sh: hold nested scopes open so jcmd can dump them try (var scope = StructuredTaskScope.open(Joiner.awaitAllSuccessfulOrThrow(), cf -> cf.withName("orders"))) { scope.fork(() -> { Thread.sleep(6000); return "A"; }); scope.fork(() -> { // subtask B opens a child scope of its own try (var child = StructuredTaskScope.open(Joiner.awaitAllSuccessfulOrThrow(), cf -> cf.withName("inventory"))) { child.fork(() -> { Thread.sleep(6000); return "B1"; }); child.join(); } return "B"; }); scope.join(); } return; } Path file = Files.createTempFile("dump", ".json"); Files.delete(file); try (var scope = StructuredTaskScope.open(Joiner.awaitAllSuccessfulOrThrow(), cf -> cf.withName("orders"))) { for (int i = 0; i < 2; i++) { int n = i; scope.fork(() -> { Thread.sleep(1500); return "task-" + n; }); } Thread.sleep(300); // let the subtasks start and block ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) .dumpThreads(file.toString(), HotSpotDiagnosticMXBean.ThreadDumpFormat.JSON); scope.join(); } String json = Files.readString(file); int at = json.indexOf("\"container\": \"orders"); int start = json.lastIndexOf('{', at); int end = json.indexOf("\"threadCount\"", at); String block = json.substring(start, end); // identity hashes, thread ids and timestamps change between runs: mask them so the transcript is stable block = block.replaceAll("@[0-9a-f]+", "@").replaceAll("\"tid\": \\d+", "\"tid\": ").replaceAll("\"owner\": \\d+", "\"owner\": "); // keep the lines that show the hierarchy: the scope, its parent and owner, and each forked thread with its own frame for (String line : block.split("\n")) { String l = line.trim(); if (l.startsWith("\"container\"") || l.startsWith("\"parent\"") || l.startsWith("\"owner\"") || l.startsWith("\"tid\"") || l.startsWith("\"virtual\"") || l.startsWith("\"state\"") || l.contains("ThreadDump.lambda")) { System.out.println(l); } } Files.deleteIfExists(file); } }