public interface Actor<T>
extends AutoCloseable
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: 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.
T - the message type| Type Params | Return Type | Name and description |
|---|---|---|
|
public void |
close()Stops this actor. |
|
public boolean |
isActive()Returns true if this actor is running and accepting messages. |
<T, R> |
public static Actor<T> |
reactor(Function<T, R> handler)Creates a stateless reactor actor. |
|
public void |
send(T message)Sends a message to this actor. |
<R> |
public Awaitable<R> |
sendAndGet(T message)Sends a message and returns an Awaitable that completes with the reply. |
<T, S> |
public static Actor<T> |
stateful(S initialState, BiFunction<S, T, S> handler)Creates a stateful actor. |
|
public void |
stop()Stops this actor gracefully. |
| Methods inherited from class | Name |
|---|---|
interface AutoCloseable |
close |
Stops this actor. Equivalent to stop().
Returns true if this actor is running and accepting messages.
Creates a stateless reactor actor. Each message is passed to the handler function, and the return value becomes the reply for sendAndGet callers.
var doubler = Actor.reactor(n -> (int) n * 2);
System.out.println(AsyncSupport.await(doubler.sendAndGet(5))); // 10
handler - the message processing functionT - the message typeR - the reply typeSends a message to this actor. The message is queued and processed asynchronously. Fire-and-forget — no reply is expected.
message - the message to sendSends a message and returns an Awaitable that completes with the reply. For reactors, the reply is the handler's return value. For stateful actors, the reply is the new state.
message - the message to sendR - the reply typeCreates a stateful actor. The handler receives the current state and the message, and returns the new state. For sendAndGet 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
}
initialState - the initial statehandler - receives (state, message), returns new stateT - the message typeS - the state typeStops this actor gracefully. Messages already in the queue are processed before the actor shuts down. New sends after stop throw IllegalStateException.