Interface Actor<T>

Type Parameters:
T - the message type
All Superinterfaces:
AutoCloseable
All Known Implementing Classes:
DefaultActor

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.

Since:
6.0.0
See Also:
  • Method Summary

    Modifier and Type
    Method
    Description
    default void
    Stops this actor.
    boolean
    Returns true if this actor is running and accepting messages.
    static <T, R> Actor<T>
    reactor(Function<T,R> handler)
    Creates a stateless reactor actor.
    void
    send(T message)
    Sends a message to this actor.
    <R> Awaitable<R>
    sendAndGet(T message)
    Sends a message and returns an Awaitable that completes with the reply.
    static <T, S> Actor<T>
    stateful(S initialState, BiFunction<S,T,S> handler)
    Creates a stateful actor.
    void
    Stops this actor gracefully.
  • Method Details

    • send

      void send(T message)
      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

      <R> Awaitable<R> sendAndGet(T message)
      Sends 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.
      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()
      Returns true if 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 throw IllegalStateException.
    • close

      default void close()
      Stops this actor. Equivalent to stop().
      Specified by:
      close in interface AutoCloseable
    • reactor

      static <T, R> Actor<T> reactor(Function<T,R> handler)
      Creates a stateless reactor actor. Each message is passed to the handler function, and the return value becomes the reply for sendAndGet(T) callers.
      
       var doubler = Actor.reactor(n -> (int) n * 2);
       System.out.println(AsyncSupport.await(doubler.sendAndGet(5))); // 10
       
      Type Parameters:
      T - the message type
      R - the reply type
      Parameters:
      handler - the message processing function
      Returns:
      a started actor
    • stateful

      static <T, S> Actor<T> stateful(S initialState, BiFunction<S,T,S> handler)
      Creates a stateful actor. The handler receives the current state and the message, and returns the new state. For sendAndGet(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 type
      S - the state type
      Parameters:
      initialState - the initial state
      handler - receives (state, message), returns new state
      Returns:
      a started actor