# Groovy Concurrent API for Java (Incubating)

version 6.0.0-RC-1

## 1. Introduction

The `groovy-concurrent-java` module provides Groovy’s concurrent and parallel API as a standalone Java library — no Groovy runtime required.

Java developers get access to:

- Structured concurrency — `AsyncScope`, `Awaitable`

- Pools — `Pool`, `ParallelScope`, `ConcurrentConfig`

- Actors — `Actor.reactor()`, `Actor.stateful()`

- Agents — `Agent` (thread-safe mutable state)

- Dataflow — `DataflowVariable`, `AsyncChannel`, `BroadcastChannel`, `ChannelSelect`

This module is published as `org.apache.groovy:groovy-concurrent-java` and contains a filtered subset of the classes from Groovy core. It must not be used alongside the full Groovy runtime — Gradle enforces mutual exclusion via a shared capability, and a runtime warning is logged if both jars are detected on the classpath.

## 2. Setup

### 2.1. Gradle

    dependencies {
        implementation 'org.apache.groovy:groovy-concurrent-java:6.0.0'
    }

### 2.2. Maven

    <dependency>
        <groupId>org.apache.groovy</groupId>
        <artifactId>groovy-concurrent-java</artifactId>
        <version>6.0.0</version>
    </dependency>

| Do not add `groovy-concurrent-java` if you already depend on `groovy` (the full runtime). The concurrent classes are included in core.

## 3. Structured Concurrency

    import groovy.concurrent.AsyncScope;
    import groovy.concurrent.Pool;
    import org.apache.groovy.runtime.async.AsyncSupport;

    // Basic scope — waits for all children before returning
    var result = AsyncScope.withScope(scope -> {
        var a = scope.async(() -> fetchUser(id));
        var b = scope.async(() -> fetchOrders(id));
        return Map.of(
            "user", AsyncSupport.await(a),
            "orders", AsyncSupport.await(b)
        );
    });

    // With a pool for executor isolation
    try (var pool = Pool.cpu()) {
        AsyncScope.withScope(pool, scope -> {
            var task = scope.async(() -> computeResult());
            return AsyncSupport.await(task);
        });
    }

## 4. Actors

    import groovy.concurrent.Actor;
    import org.apache.groovy.runtime.async.AsyncSupport;

    // Reactor — stateless, each message produces a reply
    var doubler = Actor.<Integer, Integer>reactor(n -> n * 2);
    int result = AsyncSupport.await(doubler.sendAndGet(21)); // 42
    doubler.stop();

    // Stateful — maintains state across messages
    var counter = Actor.<String, Integer>stateful(0, (state, msg) -> {
        if ("increment".equals(msg)) return state + 1;
        return state;
    });
    counter.send("increment");
    counter.send("increment");
    int count = AsyncSupport.await(counter.sendAndGet("increment")); // 3
    counter.stop();

## 5. Agents

    import groovy.concurrent.Agent;
    import org.apache.groovy.runtime.async.AsyncSupport;

    var counter = Agent.create(0);
    counter.send(n -> n + 1);
    counter.send(n -> n + 1);
    counter.send(n -> n + 1);

    int result = AsyncSupport.await(counter.getAsync()); // 3
    counter.shutdown();

## 6. Dataflow Variables

    import groovy.concurrent.Awaitable;
    import groovy.concurrent.DataflowVariable;
    import org.apache.groovy.runtime.async.AsyncSupport;

    var x = new DataflowVariable<Integer>();
    var y = new DataflowVariable<Integer>();

    // z depends on x and y — blocks until both are bound
    var z = Awaitable.<Integer>go(() ->
        AsyncSupport.await(x) + AsyncSupport.await(y)
    );

    // Bind in any order
    AsyncSupport.getExecutor().execute(() -> x.bind(10));
    AsyncSupport.getExecutor().execute(() -> y.bind(5));

    int result = AsyncSupport.await(z); // 15

## 7. Pools

    import groovy.concurrent.ParallelScope;
    import groovy.concurrent.Pool;
    import org.apache.groovy.runtime.async.AsyncSupport;

    var result = ParallelScope.withPool(4, scope -> {
        var tasks = new java.util.ArrayList<groovy.concurrent.Awaitable<Integer>>();
        for (int i = 1; i <= 4; i++) {
            int n = i;
            tasks.add(scope.async(() -> n * 10));
        }
        int sum = 0;
        for (var task : tasks) {
            sum += (int) AsyncSupport.await(task);
        }
        return sum;
    }); // 100

## 8. Features not available in the Java module

The following features require the Groovy runtime and are only available when using the full `groovy` dependency:

Feature | Reason
--- | ---
`Dataflows` class | Uses Groovy’s `propertyMissing` for dynamic property access
`async { }` / `await` keywords | Groovy language syntax, transformed by the Groovy compiler
`defer { }` / `yield return` | Groovy language syntax
`for await (x in channel)` | Groovy compiler-generated iteration
`@ActiveObject` / `@ActiveMethod` | Groovy AST transformation
Parallel collection methods (`collectParallel`, etc.) | Registered as Groovy extension methods on `Collection`
`AsyncClosureUtils` (`wrapAsync`, `wrapAsyncGenerator`) | Return `Closure` subclasses
Closure-based APIs (e.g., `scope.async { }`) | Groovy SAM coercion from Closure to `Supplier`/`Function`

Java users have full access to the underlying APIs using `java.util.function` types (`Supplier`, `Function`, `Consumer`, `Predicate`, etc.) and explicit `AsyncSupport.await()` calls instead of the `await` keyword.