Jactl brings virtual threads to Java 8 with a clever exception trick
Virtual Threads for a scripting language in Java 8 without Loom

Jactl, an embeddable scripting language for Java, implements continuations and virtual-thread-like behavior without Loom, targeting Java 8 and 11. By throwing lightweight exceptions that unwind the call stack, each Jactl frame saves its state into a chain of Continuation objects, which can be resumed later. This enables non-blocking execution in event-driven applications. The post details the mechanism, including async function tracking, resumption, checkpointing, and benchmarks showing minimal overhead.
The cost of throwing an exception is mostly in the generation of the stack trace that goes along with it. As long as you throw an exception that does not fill in the stack trace, it is actually very efficient.