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 
JCoroutineScopeAPI - Cancellation and timeout support
 - Channels with backpressure
 - Full JUnit 5 test suite
 
 - Core 
 
(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 Scheduling – 
yield(),yieldAndPause(),delay() - Cancellation – explicit checks via 
suspend.checkCancellation() - Resource Management – use try-with-resources for scopes
 
