This project contains a generator feature for Java applications using Project Loom's internal Continuation
class.
A Javadoc is available on GitHub Pages
For a demo, see io.github.danthe1st.jvmyieldreturn.example.GeneratorExamples
:
private void example() {
System.out.println("main thread: " + Thread.currentThread());
for(String s : Generator.iterable(this::someMethod)){
System.out.println("Text: " + s);
}
System.out.println();
System.out.println("Now using streams:");
Generator.stream(this::someMethod).limit(2).forEach(System.out::println);
}
private void someMethod(Generator<String> y) {
y.yield("Hello - " + Thread.currentThread());
System.out.println("between yields");
y.yield("World - " + Thread.currentThread());
for(String s : Generator.iterable(this::otherMethod)){
y.yield("nested: " + s);
}
y.yield("bye - " + Thread.currentThread());
}
private void otherMethod(Generator<String> y) {
y.yield("it can");
y.yield("also be");
y.yield("nested");
}
This demo should print
main thread: Thread[#1,main,5,main]
Text: Hello - Thread[#1,main,5,main]
between yields
Text: World - Thread[#1,main,5,main]
Text: nested: it can
Text: nested: also be
Text: nested: nested
Text: bye - Thread[#1,main,5,main]
Now using streams:
Hello - Thread[#1,main,5,main]
between yields
World - Thread[#1,main,5,main]
It can be seen that the main thread switches between the enhanced for loop and the method with the yield return
code.
It is necessary to supply the JVM arguments --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn
both for compiling and running the application.
Continuation
is an internal JDK class which is used for virtual threads.
It allows running some code using Continuation#run
until that code calls Continuation.yield
.
At this point, execution of that code stops ("Freeze") and the Continuation#run
returns.
If Continuation#run
is then called again, the said code continues ("Thaw") at the Continuation.yield
method call.
This project allows to create an Iterable
which runs some (user-provided) Function<Yielder<T>,T>
when hasNext()
or next()
is called and no value that hasn't been consumed by next()
was computed already.
When the code inside that Function
calls the Yielder#yield
method, the method is suspended and Iterator#next
returns the value passed to Yielder#yield
.
The method is resumed when Iterator#hasNext
/Iterator#next
is called again after the previous value was consumed by Iterator#next
.
The yield
ing parts of the method will always run in the same thread that also calls Iterator#hasNext
/Iterator#next
.
This project requires a Hotspot JDK version 20 (other Java versions may not work).
It is necessary to supply the arguments --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn
both for compiling and running the application.
Since Continuation
is an internal JDK class, it is normally not available.
It can be made available to this project using the command-line argument --add-exports java.base/jdk.internal.vm=YieldReturn
which allows this project (module YieldReturn
) to access classes of the package jdk.internal.vm
of the java.base
module.
The argument --enable-preview
is necessary since Continuation
s are only available as a preview feature (as of Java 20).
In Eclipse, the export can be added from the Libraries
tab of the Build path (Right click on the project > Build Path
> Configure Build Path
> Libraries
).
After expanding the JRE System Library
(this should point to a Java 20 JDK), there should be a Is modular
option.
This option needs to be edited via double-clicking or the Edit
-button on the right.
In the Details
tab, a new export needs to be added via the Add
button on the right.
Enter java.base
for the Source Module
and jdk.internal.vm
for the Package
entry.
--enable-preview
can be added to the VM arguments of the run configuration.
The content of the src
directory can be compiled and run using the javac
/java
command as follows:
First, create a directory called build
in the project root in order to store .class
files and ensure that you are running Java 20 with Hotspot.
Then, the code can be compiled using
javac --source 20 --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn -d build src/module-info.java src/io/github/danthe1st/jvmyieldreturn/*.java src/io/github/danthe1st/jvmyieldreturn/test/*.java
After the code is compiled to the build
directory, it can be run with the following command:
java --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn --module-path build -m YieldReturn/io.github.danthe1st.jvmyieldreturn.test.YieldReturnTest
Some tests are present in the test
directory.
Running the tests requires JUnit 5.
See This JVM Language Summit talk for details on how Continuation
s work in Java.
This talk heavily inspired the creation of this project.
Continuation
is not public API.
This project uses classes which may not be present in different JVMs or may be removed/changed even within minor Java updates.
This project is just for educational purposes!
If you are using Continuation
in your code, do so at your own risk.