Package groovy.concurrent
Interface Actor<T>
- Type Parameters:
T- the message type
- All Superinterfaces:
AutoCloseable
- All Known Implementing Classes:
DefaultActor
A lightweight message-passing actor for concurrent state management.
Each actor has a dedicated thread that processes messages sequentially from a queue. This guarantees that the actor's state is never accessed concurrently — no locks needed.
Two factory methods provide the common patterns:
reactor(Function)— stateless; each message produces a replystateful(Object, BiFunction)— maintains state; handler receives (state, message) and returns new state
// Reactor: stateless message processing
def doubler = Actor.reactor { msg -> msg * 2 }
assert await(doubler.sendAndGet(5)) == 10
// Stateful: accumulates state across messages
def counter = Actor.stateful(0) { state, msg ->
switch (msg) {
case 'increment': return state + 1
case 'decrement': return state - 1
default: return state
}
}
counter.send('increment')
counter.send('increment')
assert await(counter.sendAndGet('increment')) == 3
Actors use virtual threads on JDK 21+ for efficient scheduling. Millions of actors can coexist without pool tuning.
Inspired by GPars actors, Erlang processes, and Clojure agents.
- Since:
- 6.0.0
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptiondefault voidclose()Stops this actor.booleanisActive()Returnstrueif this actor is running and accepting messages.static <T,R> Actor<T> Creates a stateless reactor actor.voidSends a message to this actor.<R> Awaitable<R>sendAndGet(T message) Sends a message and returns anAwaitablethat completes with the reply.static <T,S> Actor<T> stateful(S initialState, BiFunction<S, T, S> handler) Creates a stateful actor.voidstop()Stops this actor gracefully.
-
Method Details
-
send
Sends a message to this actor. The message is queued and processed asynchronously. Fire-and-forget — no reply is expected.- Parameters:
message- the message to send- Throws:
IllegalStateException- if the actor has been stopped
-
sendAndGet
Sends a message and returns anAwaitablethat completes with the reply. For reactors, the reply is the handler's return value. For stateful actors, the reply is the new state.- Type Parameters:
R- the reply type- Parameters:
message- the message to send- Returns:
- an awaitable reply
- Throws:
IllegalStateException- if the actor has been stopped
-
isActive
boolean isActive()Returnstrueif this actor is running and accepting messages. -
stop
void stop()Stops this actor gracefully. Messages already in the queue are processed before the actor shuts down. New sends after stop throwIllegalStateException. -
close
default void close()Stops this actor. Equivalent tostop().- Specified by:
closein interfaceAutoCloseable
-
reactor
Creates a stateless reactor actor. Each message is passed to the handler function, and the return value becomes the reply forsendAndGet(T)callers.var doubler = Actor.reactor(n -> (int) n * 2); System.out.println(AsyncSupport.await(doubler.sendAndGet(5))); // 10- Type Parameters:
T- the message typeR- the reply type- Parameters:
handler- the message processing function- Returns:
- a started actor
-
stateful
Creates a stateful actor. The handler receives the current state and the message, and returns the new state. ForsendAndGet(T)callers, the new state is the reply.var counter = Actor.stateful(0, (state, msg) -> { if ("increment".equals(msg)) return (int) state + 1; return state; }); counter.send("increment"); System.out.println(AsyncSupport.await(counter.sendAndGet("increment"))); // 2- Type Parameters:
T- the message typeS- the state type- Parameters:
initialState- the initial statehandler- receives (state, message), returns new state- Returns:
- a started actor
-