JCoroutines

Structured concurrency for the JVM without the magic.

Why does concurrency in Java have to be so hard?

I asked this in my original announcement post.
Now I’m excited to say:


JCoroutines 0.1.0 Released 🎉

JCoroutines is now released and available on Maven Central!

Maven coordinates:

<dependency>
  <groupId>tech.robd</groupId>
  <artifactId>jcoroutines</artifactId>
  <version>0.1.0</version>
</dependency>

About JCoroutines

JCoroutines is a lightweight concurrency toolkit for Java 21+, inspired by Kotlin coroutines.
It provides structured concurrency with scopes, cancellation, timeouts, and channels, built on Java’s new virtual threads.

The goal: make concurrency feel clean and explicit—without needing a heavy reactive framework.

Key features

  • Structured task scopes
  • Fail-fast cancellation (siblings cancel together)
  • Timeout handling
  • Channel support with backpressure
  • Virtual-thread friendly execution

Version History

  • 0.1.0 – Initial release
    • Core JCoroutineScope API
    • Cancellation and timeout support
    • Channels with backpressure
    • Full JUnit 5 test suite

(Version history will be expanded here with each release.)


Links


Getting Started with JCoroutines

Requirements

  • Java 21+ (uses Virtual Threads)
  • No additional runtime dependencies

Installation (Gradle)

dependencies {
    implementation("tech.robd:jcoroutines:0.1.0")
}

Installation (Maven)

<dependency>
  <groupId>tech.robd</groupId>
  <artifactId>jcoroutines</artifactId>
  <version>0.1.0</version>
</dependency>

Quick Start Examples

Basic async

import tech.robd.jcoroutines.*;

JCoroutineHandle<String> handle = Coroutines.async(suspend -> {
    suspend.delay(100);
    return "Hello, Coroutines!";
});

System.out.println(handle.join());

Structured concurrency

try (var scope = new StandardCoroutineScope()) {
    var h1 = scope.async(suspend -> fetchData(suspend, "url1"));
    var h2 = scope.async(suspend -> fetchData(suspend, "url2"));

    System.out.println(h1.join());
    System.out.println(h2.join());
} // automatic cleanup & cancellation

Channels

try (var scope = new StandardCoroutineScope()) {
    var channel = InteropChannel.<String>buffered(10);

    scope.launch(suspend -> {
        for (int i = 0; i < 5; i++) {
            channel.send(suspend, "Message " + i);
            suspend.yieldAndPause(Duration.ofMillis(100));
        }
        channel.close();
    });

    scope.launch(suspend ->
        channel.forEach(suspend, (ctx, msg) ->
            System.out.println("Received: " + msg.orElse("null"))
        )
    );
}

Key Concepts

  • Suspend Functions – always take a SuspendContext
  • Cooperative Schedulingyield(), yieldAndPause(), delay()
  • Cancellation – explicit checks via suspend.checkCancellation()
  • Resource Management – use try-with-resources for scopes
Scroll to Top