1. Introduction
Coroutines are an alternative to Java Threads as they provide a way to execute interruptable tasks on a very high level of concurrency, but until Project Loom is complete, we have to look to library support to get it.
In this tutorial, we'll take a look at Quasar, one such library that offers co-routine support.
2. Setup
We'll use the latest version of Quasar which requires Java 11 or higher. But, the example application will also work with prior versions of Quasar which are compatible with Java 7 and 8.
Quasar provides three dependencies which we need to include in our build:
<dependency> <groupId>co.paralleluniverse</groupId> <artifactId>quasar-core</artifactId> <version>0.8.0</version> </dependency> <dependency> <groupId>co.paralleluniverse</groupId> <artifactId>quasar-actors</artifactId> <version>0.8.0</version> </dependency> <dependency> <groupId>co.paralleluniverse</groupId> <artifactId>quasar-reactive-streams</artifactId> <version>0.8.0</version> </dependency>
Quasar's implementation relies on bytecode instrumentation to work correctly. To perform bytecode instrumentation, we have two options:
- At compile time, or
- At runtime with the Java agent
Using the Java agent is the preferred way since it doesn't have any special build requirements and works with any setup.
2.1. Specify the Java Agent with Maven
To run the Java agent with Maven, we need to include the maven-dependency-plugin to always run the properties goal:
<plugin> <artifactId>maven-dependency-plugin</artifactId> <version>3.1.1</version> <executions> <execution> <id>getClasspathFilenames</id> <goals> <goal>properties</goal> </goals> </execution> </executions> </plugin>
The properties goal will generate a property that is pointing to the quasar-core.jar location on the classpath.
For the execution of our application we'll use the exec-maven-plugin:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.3.2</version> <configuration> <workingDirectory>target/classes</workingDirectory> <executable>echo</executable> <arguments> <argument>-javaagent:${co.paralleluniverse:quasar-core:jar}</argument> <argument>-classpath</argument> <classpath/> <argument>com.baeldung.quasar.QuasarHelloWorldKt</argument> </arguments> </configuration> </plugin>
To make use of that plugin and launch our application we will then run Maven:
mvn compile dependency:properties exec:exec
3. Implementing Coroutines
To implement the coroutine, we'll use Fibers from the Quasar library. Fibers provide lightweight threads that will be managed by the JVM instead of the operating system. Because they require very little RAM and put far less burden on the CPU, we could have millions of them in our application without having to worry about performance.
To launch a fiber, we create an instance of the Fiber<T> class which will wrap the code that we want to execute and call the start method:
new Fiber<Void>(() -> { System.out.println("Inside fiber coroutine..."); }).start();
4. Conclusion
In this article, we've introduced how to implement coroutines by using the Quasar library. What we've seen here is only a minimal working example and the Quasar library is capable of doing much more.
Please find all of the source code over on GitHub.